diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 000000000000..1866230cb54f --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1,3 @@ +{ + "spellcheck": false +} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 000000000000..018e0340ddbd --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1,4 @@ +{ + "accentColor": "", + "baseFontSize": 13 +} \ No newline at end of file diff --git a/.obsidian/core-plugins-migration.json b/.obsidian/core-plugins-migration.json new file mode 100644 index 000000000000..436f43cf561e --- /dev/null +++ b/.obsidian/core-plugins-migration.json @@ -0,0 +1,30 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "properties": false, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": false +} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 000000000000..9405bfdc224d --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,20 @@ +[ + "file-explorer", + "global-search", + "switcher", + "graph", + "backlink", + "canvas", + "outgoing-link", + "tag-pane", + "page-preview", + "daily-notes", + "templates", + "note-composer", + "command-palette", + "editor-status", + "bookmarks", + "outline", + "word-count", + "file-recovery" +] \ No newline at end of file diff --git a/.obsidian/graph.json b/.obsidian/graph.json new file mode 100644 index 000000000000..29afc6b5c0d1 --- /dev/null +++ b/.obsidian/graph.json @@ -0,0 +1,22 @@ +{ + "collapse-filter": false, + "search": "tag:#C ", + "showTags": true, + "showAttachments": false, + "hideUnresolved": true, + "showOrphans": true, + "collapse-color-groups": true, + "colorGroups": [], + "collapse-display": true, + "showArrow": false, + "textFadeMultiplier": 0, + "nodeSizeMultiplier": 1, + "lineSizeMultiplier": 1, + "collapse-forces": true, + "centerStrength": 0.518713248970312, + "repelStrength": 10, + "linkStrength": 1, + "linkDistance": 250, + "scale": 0.36288736930121895, + "close": false +} \ No newline at end of file diff --git a/.obsidian/hotkeys.json b/.obsidian/hotkeys.json new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ b/.obsidian/hotkeys.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json new file mode 100644 index 000000000000..7527278c07d1 --- /dev/null +++ b/.obsidian/workspace.json @@ -0,0 +1,205 @@ +{ + "main": { + "id": "714f4911ae7453d7", + "type": "split", + "children": [ + { + "id": "3c886135c1fe4ea5", + "type": "tabs", + "children": [ + { + "id": "61669096ec41de77", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md", + "mode": "source", + "source": false + } + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "9c19c37cdd2c1df7", + "type": "split", + "children": [ + { + "id": "8792780e3c0cf536", + "type": "tabs", + "children": [ + { + "id": "e5a4d8f3d8bcf0d4", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical" + } + } + }, + { + "id": "70aef7345187e503", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + } + } + }, + { + "id": "545fb4650a6f6b4d", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {} + } + } + ] + } + ], + "direction": "horizontal", + "width": 200 + }, + "right": { + "id": "8fdde2d36d733d55", + "type": "split", + "children": [ + { + "id": "dda76e87445e3728", + "type": "tabs", + "children": [ + { + "id": "69a768b02265e6ec", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "file": "_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md", + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "4195e1766443cfd3", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "file": "_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md", + "linksCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "8fede9336240c5ea", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true + } + } + }, + { + "id": "4cb02b8f1721f042", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "file": "_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md" + } + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:퀵 스위처 열기": false, + "graph:그래프 뷰 열기": false, + "canvas:새 캔버스 만들기": false, + "daily-notes:오늘의 데일리 노트 열기": false, + "templates:템플릿 삽입": false, + "command-palette:명령어 팔레트 열기": false + } + }, + "active": "61669096ec41de77", + "lastOpenFiles": [ + "_posts/Language/C/2023-12-04-42_CommonAndEnumeration.md", + "_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md", + "_posts/Language/C/2023-12-04-43_ConsoleIO.md", + "_site/language/42_CommonAndEnumeration/index.html", + "_site/language/42_CommonAndEnumeration", + "_posts/Language/C/2023-12-04-44_FileIO.md", + "_posts/Language/C/2023-12-04-40_PointersAndStructures.md", + "_posts/Language/C/2023-12-04-39_BasicStructure.md", + "_posts/Language/C/2023-12-04-38_StringProcessingFunction.md", + "_posts/Language/C/2023-12-04-37_StringIOFunction.md", + "_posts/Language/C/2023-12-04-34_BasicIO.md", + "_posts/Language/C/2023-12-04-30_PointerArrayAndArrayPointers.md", + "_posts/Language/C/2023-12-04-25_PointerConcept.md", + "_posts/Language/C/2023-12-04-24_MultidimensionalArrangement.md", + "_posts/Language/C/2023-12-04-23_1DArrangement.md", + "_posts/Language/C/2023-12-04-22_RecursiveCall.md", + "_posts/Language/C/2023-12-03-21_ValidRangeOfVariable.md", + "_posts/Language/C/2023-12-03-20_CLanguageFunction.md", + "_posts/Language/C/2023-12-03-19_ControlStatement.md", + "_posts/Language/C/2023-12-03-18_IterationStatement.md", + "_posts/Language/C/2023-12-03-17_ConditionalStatement.md", + "_posts/Language/C/2023-12-03-16_OtherOperator.md", + "_posts/Language/C/2023-12-03-15_BitwiseOperator.md", + "_posts/Language/C/2023-12-03-14_LogicalOperator.md", + "_posts/Language/C/2023-12-03-13_ComparisonOperator.md", + "_posts/Language/C/2023-12-03-12_IncrementAndDecrementOperator.md", + "_posts/Language/C/2023-12-03-11_AssignmentOperator.md", + "_posts/Game Development Knowledge/Design Pattern", + "_posts/Game Development Knowledge/Computer Graphic", + "_posts/Game Development Knowledge/Game Math", + "_posts/Language/C#", + "_posts/Language/C++", + "_posts/Basic Development Knowledge/Software Computer Science", + "_posts/Basic Development Knowledge/Algorithm", + "_posts/Game Development Knowledge", + "_site/Pasted image 20231207191701.png", + "Pasted image 20231207191701.png", + "_site/Pasted image 20231206205417.png", + "Pasted image 20231206205417.png", + "_site/Pasted image 20231206191149.png", + "Pasted image 20231206191149.png", + "스크린샷(753).png", + "스크린샷(753) 1.png", + "스크린샷(753) - 복사본.png", + "스크린샷(753) - 복사본 1.png", + "무제 파일.canvas", + "무제 파일 3.canvas", + "무제 파일 2.canvas", + "무제 파일 1.canvas", + "_site/무제 파일 3.canvas", + "_site/무제 파일 2.canvas", + "_site/무제 파일 1.canvas", + "_site/무제 파일.canvas" + ] +} \ No newline at end of file diff --git a/2023-12-04.md b/2023-12-04.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Gemfile b/Gemfile index 1291498971d7..cb8b26971af0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,3 @@ source "https://rubygems.org" -gemspec \ No newline at end of file +gemspec +gem "webrick", "~> 1.8" diff --git a/Pasted image 20231203135844.png b/Pasted image 20231203135844.png new file mode 100644 index 000000000000..b8f37c74e7a6 Binary files /dev/null and b/Pasted image 20231203135844.png differ diff --git a/Pasted image 20231203140231.png b/Pasted image 20231203140231.png new file mode 100644 index 000000000000..a039737df282 Binary files /dev/null and b/Pasted image 20231203140231.png differ diff --git a/Pasted image 20231203142032.png b/Pasted image 20231203142032.png new file mode 100644 index 000000000000..5957cfbe4c36 Binary files /dev/null and b/Pasted image 20231203142032.png differ diff --git a/Pasted image 20231204195434.png b/Pasted image 20231204195434.png new file mode 100644 index 000000000000..ebf74daa45fa Binary files /dev/null and b/Pasted image 20231204195434.png differ diff --git a/Pasted image 20231204212405.png b/Pasted image 20231204212405.png new file mode 100644 index 000000000000..e85490920936 Binary files /dev/null and b/Pasted image 20231204212405.png differ diff --git a/Pasted image 20231206191149.png b/Pasted image 20231206191149.png new file mode 100644 index 000000000000..efa6346607fc Binary files /dev/null and b/Pasted image 20231206191149.png differ diff --git a/Pasted image 20231206205417.png b/Pasted image 20231206205417.png new file mode 100644 index 000000000000..515a92ace312 Binary files /dev/null and b/Pasted image 20231206205417.png differ diff --git a/Pasted image 20231207191701.png b/Pasted image 20231207191701.png new file mode 100644 index 000000000000..b38d139c6378 Binary files /dev/null and b/Pasted image 20231207191701.png differ diff --git a/[.md b/[.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/_config.yml b/_config.yml index 1da3e705de83..92d48536d14a 100644 --- a/_config.yml +++ b/_config.yml @@ -12,22 +12,22 @@ # theme : "minimal-mistakes-jekyll" # remote_theme : "mmistakes/minimal-mistakes" -minimal_mistakes_skin : "default" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" +minimal_mistakes_skin : "dark" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" # Site Settings -locale : "en-US" -title : "Site Title" -title_separator : "-" -subtitle : # site tagline that appears below site title in masthead -name : "Your Name" -description : "An amazing website." -url : # the base hostname & protocol for your site e.g. "https://mmistakes.github.io" +locale : "ko-KR" +title : "DEVLOG" +title_separator : "|" +subtitle : "HELLO, WORLD!" +name : "EUNCHONG" +description : "DON’T WORRY IF IT DOESN’T WORK RIGHT. IF EVERYTHING DID, YOU’D BE OUT OF A JOB" +url : "https://EunChong999.github.io" baseurl : # the subpath of your site, e.g. "/blog" repository : # GitHub username/repo-name e.g. "mmistakes/minimal-mistakes" teaser : # path of fallback teaser image, e.g. "/assets/images/500x300.png" -logo : # path of logo image to display in the masthead, e.g. "/assets/images/88x88.png" +logo : "/assets/images/DEV.png" masthead_title : # overrides the website title displayed in the masthead, use " " for no title -# breadcrumbs : false # true, false (default) +breadcrumbs : true # true, false (default) words_per_minute : 200 comments: provider : # false (default), "disqus", "discourse", "facebook", "staticman", "staticman_v2", "utterances", "giscus", "custom" @@ -104,10 +104,10 @@ analytics: # Site Author author: - name : "Your Name" + name : "EUNCHONG" avatar : # path of avatar image, e.g. "/assets/images/bio-photo.jpg" - bio : "I am an **amazing** person." - location : "Somewhere" + bio : “DON’T WORRY IF IT DOESN’T WORK RIGHT. IF EVERYTHING DID, YOU’D BE OUT OF A JOB” + location : "South Korea" email : links: - label: "Email" @@ -257,16 +257,16 @@ tag_archive: type: liquid path: /tags/ # https://github.com/jekyll/jekyll-archives -# jekyll-archives: -# enabled: -# - categories -# - tags -# layouts: -# category: archive-taxonomy -# tag: archive-taxonomy -# permalinks: -# category: /categories/:name/ -# tag: /tags/:name/ +jekyll-archives: + enabled: + - categories + - tags + layouts: + category: archive-taxonomy + tag: archive-taxonomy + permalinks: + category: /categories/:name/ + tag: /tags/:name/ # HTML Compression @@ -290,3 +290,6 @@ defaults: comments: # true share: true related: true + show_date : true + +date_format: "%Y-%m-%d" \ No newline at end of file diff --git a/_data/navigation.yml b/_data/navigation.yml index 6f30866f3bed..47035a2645d8 100644 --- a/_data/navigation.yml +++ b/_data/navigation.yml @@ -1,7 +1,9 @@ # main links main: - - title: "Quick-Start Guide" - url: https://mmistakes.github.io/minimal-mistakes/docs/quick-start-guide/ +- title : "Category" + url : /categories/ +- title : "Tag" + url : /tags/ # - title: "About" # url: https://mmistakes.github.io/minimal-mistakes/about/ # - title: "Sample Posts" diff --git a/_pages/404.md b/_pages/404.md new file mode 100644 index 000000000000..4eb2f2c233da --- /dev/null +++ b/_pages/404.md @@ -0,0 +1,8 @@ +--- +title: "Page Not Found" +excerpt: "Page not found. Your pixels are in another canvas." +sitemap: false +permalink: /404.html +--- + +![](assets\images\404.png) diff --git a/_pages/category-archive.md b/_pages/category-archive.md new file mode 100644 index 000000000000..2a2d3f2f03c5 --- /dev/null +++ b/_pages/category-archive.md @@ -0,0 +1,7 @@ +--- +title : "Category" +layout : categories +permalink : /categories/ +author_profile : true +sidebar_main : true +--- \ No newline at end of file diff --git a/_pages/tag-archive.md b/_pages/tag-archive.md new file mode 100644 index 000000000000..5ab57ae2b6f8 --- /dev/null +++ b/_pages/tag-archive.md @@ -0,0 +1,7 @@ +--- +title : "Tag" +layout : tags +permalink : /tags/ +author_profile : true +sidebar_main : true +--- \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-01_C.md b/_posts/Language/C/2023-12-03-01_C.md new file mode 100644 index 000000000000..e7f8a2116291 --- /dev/null +++ b/_posts/Language/C/2023-12-03-01_C.md @@ -0,0 +1,92 @@ +--- +layout: single +title: Chapter 01 C 언어 +date: 2023-12-03 11:55:25 +09:00 +categories: Language +tags: C +excerpt: C 언어에 관한 글입니다. +toc: true +--- + +# 1 프로그램(program) + +- 프로그램(program) + +> 프로그램(program)이란 어떤 문제를 해결하기 위해 컴퓨터에게 주어지는 +> 처리 방법과 순서를 기술한 일련의 명령문의 집합체를 의미한다. + +## 1.1 프로그래밍 언아(programming language) + +- 프로그래밍 언아(programming language) + +> 프로그래밍 언아(programming language)란 기계(컴퓨터)에게 +> 명령이나 연산을 시킬 목적으로 설계되어 기계와 의사소통을 할 수 있게 해주는 언어를 의미한다. + +### 1.1.1 프로그래밍 언어의 분류 + +> 프로그래밍 언어는 크게 저급 언어(low-level language)와 고급 언어(high-level language)로 나뉜다. +> 저급 언어와 고급 언어는, 기계가 이해하기 쉬운가(저급 언어), +> 사람이 이해하기 쉬운가(고급 언어)를 상대적으로 나눈 개념이라고 할 수 있다. + +- 저급 언어(low-level language) + +> 저급 언어(low-level language)란 컴퓨터가 이해하기 쉽게 작성된 프로그래밍 언어를 의미한다. + +> 저급 언어는 실행 속도가 매우 빠르지만, 사람이 배우기에는 매우 어려워 프로그램의 유지보수가 힘들다. + +> 대표적인 언어로는 기계어(machine language)와 어셈블리어(assembly language) 등이 있다. + +- 고급 언어(high-level language) + +> 고급 언어(high-level language)란 컴퓨터보다는 사람이 알기 쉽도록 작성된 프로그래밍 언어를 의미한다. + +> 고급 언어는 컴파일러나 인터프리터에 의해 기계가 이해 할 수 있는 언어로 번역되어 실행 된다. +> 저급 언어보다 상대적으로 실행 속도가 느리지만, 저급 언어에 비해 가독성이 높고 다루기가 쉽다. + +> 대표적인 언어로는 자바와 파이썬 등이 있다. + +> C 언어는 저급 언어와 고급 언어의 특징을 모두 가지고 있는 +> 절차 지향 프로그래밍 언어(procedure-oriented programming language)이다. + +# 2 C 언어 + +## 1.1 C 언어의 역사 + +> C 언어는 1972년 벨 연구소의 켄 톰프슨(Kenneth Thompson)과 데니스 리치(Dennis Ritchie)가 +> 유닉스(UNIX) 운영체제에서 사용하기 위해 개발한 범용적인 고급 언어이다. + +> A 언어라고 불리는 ALGOL 60부터, CPL, BCPL을 거쳐, +켄 톰프슨이 B 언어를 개발하게 된다. +이후 데니스 리치가 B언어를 좀 더 개선하여 지금의 C 언어를 만들게 된다. +C 언어라는 이름의 유래 또한 B 언어 바로 다음에 개발되어서 명명된 이름이다. + +## 1.2 C 언어의 탄생 배경 + +>유닉스 운영체제는 C 언어 이전에 어셈블리어라는 저급 언어를 사용했다. +하지만 어셈블리어는 특정 하드웨어에 종속적인 언어여서, +이 언어로 작성된 프로그램은 다른 하드웨어로 이식할 수 없었다. +즉, 하나의 기능을 하는 프로그램을 CPU의 종류만큼 여러 번 작성해야만 했던 것이다. +따라서 이식성도 좋고 어셈블리어보다 쉬운 언어가 필요해졌고, +그래서 개발된 언어가 바로 C 언어이다. + +> 현재 널리 사용되는 모든 운영체제의 커널은 대부분 C 언어를 이용해 구현되어 있다. +이처럼 C 언어는 시스템 프로그래밍에 가장 잘 어울리지만, +응용 프로그래밍에도 많이 사용되는 프로그래밍 언어이다. + +## 1.3 C 언어의 특징 + +### 1.3.1 C 언어의 장점 + +1. C 언어로 작성된 프로그램은 다양한 하드웨어로의 이식성이 좋다. + +2. C 언어는 절차 지향 프로그래밍 언어로, 코드가 복잡하지 않아 상대적으로 유지보수가 쉽다. + +3. C 언어는 저급 언어의 특징을 가지고 있으므로, 어셈블리어 수준으로 하드웨어를 제어할 수 있다. + +4. C 언어는 코드가 간결하여, 완성된 프로그램의 크기가 작고 실행 속도가 빠르다. + +### 1.3.2 C 언어의 단점 + +1. C 언어는 저급 언어의 특징을 가지고 있으므로, 자바와 같은 다른 고급 언어보다 배우기가 쉽지 않다. + +2. C 언어는 다른 언어와는 달리 시스템 자원을 직접 제어할 수 있으므로, 프로그래밍하는데 세심한 주의를 기울여야 한다. diff --git a/_posts/Language/C/2023-12-03-02_CProgramming.md b/_posts/Language/C/2023-12-03-02_CProgramming.md new file mode 100644 index 000000000000..4af1de108548 --- /dev/null +++ b/_posts/Language/C/2023-12-03-02_CProgramming.md @@ -0,0 +1,101 @@ +--- +layout: single +title: Chapter 02 C 프로그래밍 +date: 2023-12-03 11:55:35 +09:00 +categories: Language +tags: C +excerpt: C 프로그래밍에 관한 글입니다. +toc: true +--- + +# 1 프로그래밍(programming) + +- 프로그래밍(programming) + +> 프로그래밍(programming)이란 목적에 맞는 알고리즘으로부터 프로그래밍 언어를 사용하여 +> 구체적인 프로그램을 작성하는 과정을 의미한다. + +> 작성된 프로그램은 먼저 실행 파일(executable file)로 변환되어야 실행할 수 있다. + +> C 언어에서 실행 파일을 생성하는 순서는 다음 그림과 같다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/42cd72ab-81eb-4917-8a31-9011d450546b) + +1. 소스 파일(source file)의 작성 + +2. 선행처리기(preprocessor)에 의한 선행처리 + +3. 컴파일러(compiler)에 의한 컴파일 + +4. 링커(linker)에 의한 링크 + +5. 실행 파일(executable file)의 생성 + +## 1.1 소스 파일(source file)의 작성 + +> 프로그래밍에서 가장 먼저 해야 할 작업은 바로 프로그램을 작성하는 것이다. + +- 소스 파일(source file) + +> 소스 파일(source file)이란 C 언어를 사용하여 문법에 맞게 논리적으로 작성된 프로그램을 의미한다. +> 소스 파일을 원시 파일이라고도 한다. + +> C 언어를 통해 작성된 소스 파일의 확장자는 .c 가 된다. + +## 1.2 선행처리기(preprocessor)에 의한 선행처리 + +- 선행처리(preprocess) + +> 선행처리(preprocess)란 소스 파일 중에서도 선행처리 문자(#)로 시작하는 선행처리 지시문의 처리 작업을 의미한다. + +> 선행처리 작업은 선행처리기(preprocessor)가 수행한다. + +> 선행처리기는 코드를 생성하는 것이 아닌, 컴파일하기 전 컴파일러가 작업하기 좋도록 +> 소스를 재구성해주는 역할만을 한다. + +## 1.3 컴파일러(compiler)에 의한 컴파일 + +> 컴퓨터는 0과 1로 이루어진 이진수로 작성된 기계어만을 이해할 수 있다. + +> 소스 파일은 개발자에 의해 C 언어로 작성되므로, 컴퓨터는 그것을 바로 이해할 수 없다. + +- 컴파일(compile) + +> 컴파일(compile)이란 소스 파일을 컴퓨터가 알아볼 수 있는 기계어로 변환시키는 작업을 의미한다. + +- 오브젝트 파일(object file) + +> 오브젝트 파일(object file)이란 컴파일러에 의해 수행된 컴파일이 끝나 기계어로 변환된 파일을 의미한다. + +> 이러한 오브젝트 파일의 확장자는 .o 나 .obj 가 된다. + +## 1.4 링커(linker)에 의한 링크 + +> 컴파일러에 의해 생성된 오브젝트 파일은 운영체제와의 인터페이스를 담당하는 +> 시동 코드(start-up code)를 가지고 있지 않다. + +- 시동 코드(start-up code) + +> 시동 코드(start-up code)란 운영체제와의 인터페이스를 담당하는 코드를 의미한다. + +> 또한, 오브젝트 파일은 대부분의 C 프로그램에서 사용하는 C 표준 라이브러리 파일도 포함되어 있지 않다. + +- 링크(link) + +> 링크(link)란 하나 이상의 오브젝트 파일과 라이브러리 파일, +> 시동 코드 등을 합쳐 하나의 파일로 만드는 작업을 의미한다. + +> 링크는 링커(linker)에 의해 수행되며, 링크가 끝나면 하나의 새로운 실행 파일이나 라이브러리 파일이 생성된다. + +- 분할 컴파일 + +> 분할 컴파일이란 여러 개의 소스 파일을 작성하여 최종적으로 링크를 통해 하나의 실행 파일로 만드는 것을 의미한다. + +## 1.5 실행 파일(executable file)의 생성 + +> 소스 파일은 선행처리기, 컴파일러 그리고 링커에 의해 일정한 과정을 거쳐 실행 파일로 변환된다. + +> 최근 사용되는 개발 툴은 대부분 위에서 소개한 선행처리기, 컴파일러, 링커를 모두 내장하고 있으므로, +> 소스 파일에서 한 번에 실행 파일을 생성해 준다. + +> 이렇게 생성된 실행 파일의 확장자는 .exe 가 된다. diff --git a/_posts/Language/C/2023-12-03-03_CProgram.md b/_posts/Language/C/2023-12-03-03_CProgram.md new file mode 100644 index 000000000000..756eb913652c --- /dev/null +++ b/_posts/Language/C/2023-12-03-03_CProgram.md @@ -0,0 +1,171 @@ +--- +layout: single +title: Chapter 03 C 프로그램의 특징 +date: 2023-12-03 11:55:41 +09:00 +categories: Language +tags: C +excerpt: C 프로그램의 특징에 관한 글입니다. +toc: true +--- + +# 1 C 프로그램의 특징 + +> C 언어로 작성된 프로그램이 가지는 일반적인 특징은 다음과 같다. + +1. C 프로그램의 기본 단위는 함수이다. + +2. 함수 내의 각 명령문은 세미콜론(;)으로 끝나야 한다. + +3. C 언어는 대소문자를 구분한다. + +4. C 언어는 자유 형식(free-format)을 허용한다. + +## 1.1 C 프로그램의 기본 단위는 함수이다. + +> C 프로그램은 하나 또는 그 이상의 함수(function)로 이루어진다. +> 또한, C 언어로 구현되는 모든 프로그램은 반드시 main() 함수를 가지고 있어야 한다. +> C 프로그램이 실행되면 컴퓨터는 제일 먼저 main() 함수를 찾아서 호출하기 때문이다. + +- 예제 + +```c +#include +#define TEXT "Welcome to C Programming!!" + +int main() +{ + return 0; // main() 함수의 모든 명령문을 수행한 후에는 0을 반환함. +} +``` + +## 1.2 함수 내의 각 명령문은 세미콜론(;)으로 끝나야 한다. + +> 함수는 언제나 기능을 가지고 있어야 한다. + +- 명령문(statement) + +> 명령문(statement)이란 C 언어에서 기능을 정의하기 위해 사용되는 문장을 의미한다. + +> 함수 내의 명령문은 언제나 위에서부터 아래로 순차적으로 실행되며, 언제나 세미콜론(;)으로 끝나야 한다. + +- 예제 + +```c +printf("C 언어"); // 정상적으로 출력됨. +printf("C 언어") // 오류가 발생함. +``` + +## 1.3 C 언어는 대소문자를 구분한다. + +> C 언어에서 변수나 함수의 이름을 작성할 때, 키워드나 예약어 등을 사용할 때는 대소문자를 정확히 구분하여 사용해야 한다. + +- 예제 + +```c +printf("C 언어"); // 정상적으로 출력됨. +Printf("C 언어") // 오류가 발생함. +``` + +## 1.4 C 언어는 자유 형식(free-format)을 허용한다. + +> C 언어에서는 문법만 맞으면 여러 개의 명령문을 한 줄에 쓸 수도 있고, 하나의 명령문을 여러 줄에 나누어 쓸 수도 있다. + +> 하지만 프로그램의 구조를 한눈에 파악할 수 있도록, 될 수 있으면 들여쓰기 등을 잘 활용하여 보기 좋게 작성하는 것이 좋다. + +> 다음 두 예제는 정확히 같은 동작을 수행한다. + +- 예제 + +```c +int func() { printf("C언어는 재밌어요!"); } +``` + +- 예제 + +```c +int func() +{ + printf("C언어는 재밌어요!"); +} +``` + +# 2 주석(comments) + +- 주석(comments) + +>주석(comment)이란 프로그래머를 위해 소스 코드 상에 직접 기술된 일종의 설명글을 의미한다. + +>주석은 컴파일 시 무시되어 프로그램 수행에는 전혀 영향을 미치지 않는다. +> 또한, 코드에 대한 이해를 돕는 설명을 적거나 디버깅을 위해 작성한다. + +> C 언어 주석의 장점은 프로그램 내의 어디에나 올 수 있다는 점이다. + 또한, C 언어의 한 줄 주석은 시작위치에 //을 사용하고, + 여러 줄 주석은 /*로 시작해서 반드시 */로 끝나야 한다. + +## 2.1 주석의 종류 + +> C 언어의 한 줄 주석은 시작위치에 //을 사용하고, +> 여러 줄 주석은 /*로 시작해서 반드시 */로 끝나야 한다. + +- 문법 + +```c +// 한 줄 주석 + +/* 여러 + + 줄 + + 주석 */ +``` + +## 2.2 주석의 중첩 + +> 다음 예제는 여러 줄 주석 안에 또 다른 한 줄 주석을 중첩해서 삽입하는 예제이다. + +- 예제 + +```c +/* 여러 줄 + + // 이렇게 두 줄 주석 안에 또 다른 한 줄 주석을 삽입할 수 있습니다. + +주석입니다. */ +``` + +> 위의 예제처럼 C 언어에서는 여러 줄 주석 안에 또 다른 한 줄 주석은 삽입할 수 있다. + +> 하지만 다음 예제처럼 여러 줄 주석 안에 또 다른 여러 줄 주석은 중첩해서 삽입할 수 없다. + +- 예제 + +```c +① /* 여러 줄 + +② /* 또 다른 여러 줄 주석입니다. */ + +③ 주석입니다. */ +``` + +> 위의 예제처럼 여러 줄 주석 안에 또 다른 여러 줄 주석을 삽입하면, ②번 라인에서 삽입한 주석의 종료 기호(*/)를 ①번 라인에서 시작한 첫 번째 주석이 자신의 종료 기호(*/)로 잘못 인식하게 된다. 위 예제의 ③번 라인은 주석으로 인식되지 못하고, 컴파일 시 오류가 발생하게 된다. + +> C 언어에서 여러 줄 주석은 절대로 중첩하여 사용해서는 안 된다. + +> 다음 예제는 여러 주석을 추가한 예제이다. + +- 예제 + +```c +#include +#define TEXT "Welcome to C Programming!!" + +/* 여기서부터 main() 함수가 시작됨. + + 작성자 : 홍길동 */ + +int main() +{ + printf(TEXT); // printf() 함수는 인수로 전달받은 데이터를 출력해주는 함수임. + return 0; // main() 함수의 모든 명령문을 수행한 후에는 0을 반환함. +} +``` diff --git a/_posts/Language/C/2023-12-03-04_Printf().md b/_posts/Language/C/2023-12-03-04_Printf().md new file mode 100644 index 000000000000..52c127bb783e --- /dev/null +++ b/_posts/Language/C/2023-12-03-04_Printf().md @@ -0,0 +1,183 @@ +--- +layout: single +title: Chapter 04 printf() 함수 +date: 2023-12-03 11:56:03 +09:00 +categories: Language +tags: C +excerpt: printf() 함수에 관한 글입니다. +toc: true +--- + +# 1 C 언어 표준 입출력 함수 + +- 입출력 함수(Input Output Function) + +> 입출력 함수(Input Output Function)란 사용자가 프로그램과 대화하기 위해 사용하는 함수를 의미한다. +> 입출력 함수를 I/O 함수라고도 한다. + +>printf() 함수와 scanf() 함수는 C 언어 표준 입출력 함수 중에서도 가장 많이 사용되는 대표적인 입출력 함수이다. + +## 1.1 출력 함수(printf)의 사용법 + +> printf() 함수는 C 언어의 표준 출력 함수로, +> 여러 종류의 데이터(data)를 다양한 서식에 맞춰 출력할 수 있게 해준다. + +> printf() 함수의 원형은 다음과 같다. + +- 함수 원형 + +```c +#include +int printf(const char * restrict format, ...); +``` + +> printf() 함수의 f는 formatted의 약자이며, 서식화된 출력을 지원한다는 의미이다. + +> 이 함수는 출력할 데이터를 어떤 서식에 맞춰 출력할지 서식 지정자(format specifier)를 통해 직접 지정할 수 있다. + +- 예제 + +```c +printf("printf() 함수는 서식 지정자를 통해 출력할 데이터의 서식을 지정할 수 있습니다!\n"); +printf("변수에 저장된 숫자는 %d입니다.", 10); +``` + +- 실행 결과 + +```c +printf() 함수는 서식 지정자를 통해 출력할 데이터의 서식을 지정할 수 있습니다! +변수에 저장된 숫자는 10입니다. +``` + +> 위의 예제에서는 int형 데이터를 나타내기 위해서 '%d'라는 서식 지정자를 사용했다. +또한, 줄 바꿈은 '\n'라는 이스케이프 시퀀스를 사용하여 표현하고 있다. + +## 1.2 이스케이프 시퀀스(escape sequence) + +- 이스케이프 시퀀스(escape sequence) + +> 이스케이프 시퀀스(escape sequence)란 컴퓨터와 주변 기기의 상태를 +바꾸는 데에 쓰이는 일련의 문자열을 의미한다. + +>이스케이프 시퀀스는 프로그램의 결과가 화면에 출력될 때 사용하게 될 특수한 문자를 위해 만들어졌다. + +> C 언어에서 사용되는 이스케이프 시퀀스는 다음과 같다. + +![](https://velog.velcdn.com/images/ecg/post/512d0512-862b-4b0d-8fae-f706261f1190/image.png) + +> 이스케이프 시퀀스 중에서 '\f'와 '\v'는 프린터로 출력할 때에만 의미를 가진다. + + +- 예제 + +```c +printf("C언어에서 사용하는 \"특수 문자\"에는 여러가지가 있습니다.\n"); +printf("\t특수 문자의 바로 앞에는 언제나 \\가 와야 합니다."); +``` + +- 실행 결과 + +```c +C언어에서 사용하는 "특수 문자"에는 여러가지가 있습니다. + 특수 문자의 바로 앞에는 언제나 \가 와야 합니다. +``` + +## 1.3 서식 지정자(format specifier) + +- 서식 지정자(format specifier) + +> 서식 지정자(format specifier)란 컴퓨터가 어떤 정보를 어떻게 해석할 건지를 지정해주는 걸 의미한다. + +>printf() 함수에서는 이러한 서식 지정자를 통해 출력할 데이터의 서식을 사용자가 직접 지정할 수 있다. + +> C 언어에서 사용되는 대표적인 서식 지정자는 다음과 같다. + +![](https://velog.velcdn.com/images/ecg/post/9510eedb-bbcd-49c6-a41f-8194fbc11ee7/image.png) + +- 예제 + +```c +printf("%%c를 사용한 결과 : %c\n", 'a'); // 문자 +printf("%%s를 사용한 결과 : %s\n", "즐거운 C언어"); // 문자열 + +printf("%%f를 사용한 결과 : %f\n", 0.123456); +printf("%%f를 사용한 결과 : %f\n", 0.123456789); // 소수점 6자리까지만 표현 + +printf("%%o를 사용한 결과 : %o\n", 123); // 8진 정수 +printf("%%x를 사용한 결과 : %x\n", 123); // 16진 정수 + +printf("%%g를 사용한 결과 : %g\n", 0.001234); // 값에 따라 %f나 %e +printf("%%g를 사용한 결과 : %g\n", 0.00001234); // 값에 따라 %f나 %e +printf("%%G를 사용한 결과 : %G\n", 0.000001234); // 값에 따라 %f나 %E +``` + +- 실행 결과 + +```c +%c를 사용한 결과 : a +%s를 사용한 결과 : 즐거운 C언어 +%f를 사용한 결과 : 0.123456 +%f를 사용한 결과 : 0.123457 +%o를 사용한 결과 : 173 +%x를 사용한 결과 : 7b +%g를 사용한 결과 : 0.001234 +%g를 사용한 결과 : 1.234e-05 +%G를 사용한 결과 : 1.234E-06 +``` + +### 1.3.1 서식 지정자의 동시 사용 + +> 여러 개의 서식 지정자를 동시에 사용하여, 여러 개의 데이터에 서로 다른 서식을 지정해 출력할 수 있다. +단, 이때 서식 지정자의 순서와 타입은 출력할 데이터의 순서와 타입과 반드시 일치해야 한다. + +- 예제 + +```c +printf("저장된 정수는 %d이며, 저장된 문자열은 %s입니다.\n", 123, "C언어"); +``` + +- 실행 결과 + +```c +저장된 정수는 123이며, 저장된 문자열은 C언어입니다. +``` + +### 1.3.2 출력 필드의 폭 설정 + +> 서식 지정자의 '%'기호와 타입을 나타내는 영문자 사이에 숫자를 추가하여 출력되는 필드의 폭을 직접 설정할 수 있다. + +> 내부의 숫자는 오른쪽 정렬이 기본이며, +> 숫자 앞에 '-'기호를 붙여 왼쪽 정렬로 변경하거나 +'+'기호를 붙여 숫자를 오른쪽 정렬한 상태에서는 +양수에 '+'기호를, 음수에 '-'기호를 붙여서 출력한다. +이때 소수 부분의 숫자는 출력되는 소수의 자릿수를 명시한다. + +- 예제 + +```c +printf(" %%d를 사용한 결과 : |%d|\n", 123); +printf(" %%7d를 사용한 결과 : |%7d|\n", 123); +printf(" %%+7d를 사용한 결과 : |%+7d|\n", 123); +printf(" %%-7d를 사용한 결과 : |%-7d|\n\n", 123); + +printf(" %%f를 사용한 결과 : |%f|\n", 1.23); +printf(" %%.1f를 사용한 결과 : |%.1f|\n", 1.23); +printf(" %%7.2f를 사용한 결과 : |%7.2f|\n", 1.23); +printf("%%+7.2f를 사용한 결과 : |%+7.2f|\n", 1.23); +printf("%%-7.2f를 사용한 결과 : |%-7.2f|\n\n", 1.23); +``` + +- 실행 결과 + +```c + %d를 사용한 결과 : |123| + %7d를 사용한 결과 : | 123| + %+7d를 사용한 결과 : | +123| + %-7d를 사용한 결과 : |123 | + + %f를 사용한 결과 : |1.230000| + %.1f를 사용한 결과 : |1.2| + %7.2f를 사용한 결과 : | 1.23| +%+7.2f를 사용한 결과 : | +1.23| +%-7.2f를 사용한 결과 : |1.23 | +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-05_Scanf().md b/_posts/Language/C/2023-12-03-05_Scanf().md new file mode 100644 index 000000000000..fe3c78a8419d --- /dev/null +++ b/_posts/Language/C/2023-12-03-05_Scanf().md @@ -0,0 +1,142 @@ +--- +layout: single +title: Chapter 05 scanf() 함수 +date: 2023-12-03 11:56:41 +09:00 +categories: Language +tags: C +excerpt: scanf() 함수에 관한 글입니다. +toc: true +--- + +# 1 scanf() 함수 + +> scanf() 함수는 C 언어의 표준 입력 함수로, +> 사용자로부터 다양한 데이터를 다양한 서식에 맞춰 입력받을 수 있게 해준다. + +> scanf() 함수의 원형은 다음과 같다. + +- 함수 원형 + +```c +#include +int scanf(const char * restrict format, ...); +``` + +> scanf() 함수의 f는 formatted의 약자이며, 서식화된 입력을 받는다는 의미이다. +이 함수는 입력받은 데이터를 어떤 서식으로 변환할지 서식 지정자(format specifier)를 통해 직접 지정할 수 있다. + +> 다음 예제는 사용자로부터 정수를 두 번 입력받아서 그 합을 출력하는 예제이다. + +- 예제 + +```c +#include +int main(void) +{ + int num01, num02; + + printf("첫 번째 정수를 입력하세요 : "); + scanf("%d", &num01); + printf("두 번째 정수를 입력하세요 : "); + scanf("%d", &num02); + + printf("입력하신 두 정수의 합은 %d입니다.\n", num01 + num02); + return 0; + +} +``` + +- 실행 결과 + +```c +첫 번째 정수를 입력하세요 : 10 +두 번째 정수를 입력하세요 : 20 +입력하신 두 정수의 합은 30입니다. +``` + +> C 언어에서 데이터를 입력받으려면 입력받고자 하는 데이터의 타입에 해당하는 크기의 메모리를 우선 할당받아야 한다. + +- 변수(variable) + +>변수(variable)란 데이터를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 의미한다. + +> scanf() 함수에 포함된 '&'기호는 주소 연산자(&)라고 한다. +이 주소 연산자는 입력받은 데이터를 뒤에 나오는 변수에 저장하라는 의미이다. + +# 2 서식 지정자의 동시 사용 + +> 여러 개의 서식 지정자를 동시에 사용하여, +여러 데이터를 서로 다른 서식으로 한 번에 입력받을 수 있다. +단, 이때에는 서식 지정자의 순서와 저장할 변수의 순서가 반드시 같아야 한다. +입력받는 데이터의 구분은 공백(줄 바꿈, 탭, 띄어쓰기 등)을 기준으로 삼는다. + +> 다음 예제는 사용자로부터 두 개의 정수를 한 번에 입력받아, +> 각각 8진수와 16진수로 출력하는 예제이다. + +- 예제 + +```c +#include +int main(void) +{ + int num01, num02; + + printf("두 개의 정수를 입력하세요 : "); + scanf("%d %d", &num01, &num02); + + printf("입력하신 두 정수를 8진수로 나타내면 %o와 %o가 되고,\n", num01, num02); + printf("입력하신 두 정수를 16진수로 나타내면 %x와 %x가 됩니다.\n", num01, num02); + return 0; +} +``` + +- 실행 결과 + +``` +두 개의 정수를 입력하세요 : 10 20 +입력하신 두 정수를 8진수로 나타내면 12와 24가 되고, +입력하신 두 정수를 16진수로 나타내면 a와 14가 됩니다. +``` + +# 3 double형 실수의 입력 + +> scanf() 함수로 float형 실수를 입력받을 때는 서식 지정자로 '%f'를 사용하면 된다. +하지만 double형 실수를 입력받을 때는 printf() 함수에서처럼 '%f'를 사용하면 안 된다. +scanf() 함수로 double형 실수를 입력받을 때는 반드시 '%lf' 서식 지정자를 사용해야 정확한 값으로 입력받을 수 있다. + +> 다음 예제는 사용자로부터 두 개의 실수를 한 번에 입력받아 출력하는 예제이다. + +- 예제 + +```c +#include +int main(void) +{ + float num01; + double num02; + + printf("두 개의 실수를 입력하세요 : "); + scanf("%f %f", &num01, &num02); + printf("입력하신 두 실수는 %f와 %f입니다.\n", num01, num02); + printf("입력받은 두 실수 중 두 번째 double형 변수에는 전혀 다른 값이 저장되었습니다.\n\n"); + + printf("다시 한 번 두 개의 실수를 입력하세요 : "); + scanf("%f %lf", &num01, &num02); + printf("입력하신 두 실수는 %f와 %f입니다.\n", num01, num02); + printf("이번에는 두 실수 모두 제대로 저장되었습니다.\n"); + return 0; + +} +``` + +- 실행 결과 + +```c +두 개의 실수를 입력하세요 : 1.2 3.4 +입력하신 두 실수는 1.200000와 0.000000입니다. +입력받은 두 실수 중 두 번째 double형 변수에는 전혀 다른 값이 저장되었습니다. + +다시 한 번 두 개의 실수를 입력하세요 : 1.2 3.4 +입력하신 두 실수는 1.200000와 3.400000입니다. +이번에는 두 실수 모두 제대로 저장되었습니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-06_Variable.md b/_posts/Language/C/2023-12-03-06_Variable.md new file mode 100644 index 000000000000..31cb6ba4352c --- /dev/null +++ b/_posts/Language/C/2023-12-03-06_Variable.md @@ -0,0 +1,173 @@ +--- +layout: single +title: Chapter 06 변수 +date: 2023-12-03 11:56:51 +09:00 +categories: Language +tags: C +excerpt: 변수에 관한 글입니다. +toc: true +--- + +# 1 변수(variable) + +- 변수(variable) + +> 변수(variable)란 데이터(data)를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 의미한다. +> 즉, 변수란 데이터(data)를 저장할 수 있는 메모리 공간을 의미하며, 이렇게 저장된 값은 변경될 수 있다. + +> C 언어에서 숫자 표현에 관련된 변수는 정수형 변수와 실수형 변수로 구분할 수 있다. +또다시 정수형 변수는 char형, int형, long형 변수로, 실수형 변수는 float형, double형 변수로 나눌 수 있다. + +> 또한, 데이터가 저장된 메모리의 주소를 저장하고 처리하는 포인터 변수가 있다. +관련된 정보를 한 번에 묶어서 처리하는 사용자 정의 구조체 변수도 있다. + +## 1.1 변수의 이름 생성 규칙 + +> C 언어에서는 변수의 이름을 비교적 자유롭게 지을 수 있다. +하지만 변수의 이름은 해당 변수에 저장될 데이터의 의미를 잘 나타내도록 짓는 것이 가장 좋다. + +> C 언어에서 변수의 이름을 생성할 때에 반드시 지켜야 하는 규칙은 다음과 같다. + +1. 변수의 이름은 영문자(대소문자), 숫자, 언더스코어(_)로만 구성된다. + +2. 변수의 이름은 숫자로 시작될 수 없다. + +3. 변수의 이름 사이에는 공백을 포함할 수 없다. + +4. 변수의 이름으로 C 언어에서 미리 정의된 키워드(keyword)는 사용할 수 없다. + +> 다음 표는 변수의 이름을 생성할 때에 지겨야하는 규칙의 예시이다. + +![스크린샷(754)](https://github.com/EunChong999/EunChong999/assets/136239807/8a2f30b2-a9ef-4b99-adc1-0a338c989299) + +> C 언어에서는 변수의 이름에 대소문자를 구분하므로 이 점에 주의해야 한다. +ex) int tcp 과 int Tcp 는 같은 변수가 아니다. + +> 다음은 C 언어에서 사용되는 키워드(Keyword)들이다. + +- 키워드(Keyword) + +> 키워드(Keyword)란 고유한 의미를 가지는 예약어를 의미한다. + +> C 언어에는 32개의 키워드가 있으며, 이러한 키워드들은 미국표준협회 ANSI에서 지정한 키워드들이다. +> 아래의 키워드들은 위의 예시처럼 변수의 이름으로 사용할 수 없다. + +![스크린샷(755)](https://github.com/EunChong999/EunChong999/assets/136239807/f6eec46a-c5c1-4b57-9a4c-704044b3b4e4) + +## 1.2 비트(bit)와 바이트(byte) + +> 컴퓨터는 모든 데이터를 2진수로 표현하고 처리한다. + +- 비트(bit) + +> 비트(bit)란 컴퓨터가 데이터를 처리하기 위해 사용하는 데이터의 최소 단위를 의미한다. + +> 이러한 비트에는 2진수의 값(0과 1)을 단 하나만 저장할 수 있다. + +- 바이트(byte) + +> 바이트(byte)란 비트가 8개 모여서 구성되며, 한 문자를 표현할 수 있는 최소 단위를 의미한다. + +## 1.3 변수와 메모리 구조 + +> 변수는 기본적으로 메모리의 주소(address)를 기억하는 역할을 한다. + +- 메모리 주소 + +> 메모리 주소란 물리적인 메모리 공간을 서로 구분하기 위해 사용되는 일종의 식별자를 의미한다. +즉, 메모리 주소란 메모리 공간에서의 정확한 위치를 식별하기 위한 고유 주소를 의미한다. + +> 변수를 참조할 때는 메모리의 주소를 참조하는 것이 아닌, +> 해당 주소에 저장된 데이터를 참조하게 된다. +> 따라서 변수는 데이터가 저장된 메모리의 주소뿐만 아니라, +> 저장된 데이터의 길이와 형태에 관한 정보도 같이 기억해야 한다. + +> 다음 그림은 메모리 상에 변수가 어떤 식으로 저장되는지를 보여준다. + +![스크린샷(756)](https://github.com/EunChong999/EunChong999/assets/136239807/29f0fe48-c5bc-4f6d-8184-5050e35bde2f) + +> 위의 그림처럼 하나의 메모리 공간에는 8개의 비트로 이루어진 1바이트의 데이터가 저장된다. +따라서 메모리의 주소 또한 1바이트씩 증가되며, 낮은 주소부터 차례대로 데이터가 저장된다. +위의 그림에서 변수의 길이가 총 4개의 메모리 공간을 포함하므로, 해당 변수에는 4바이트의 데이터가 저장되어 있다. + +> 이때 변수의 이름은 첫 번째 메모리 주소인 0x10만을 가리키게 된다. +따라서 변수의 길이가 4이며, 변수가 어떤 형태로 구성되는지도 알아야만 +해당 변수에서 데이터를 올바르게 참조할 수 있다. + +## 1.4 변수의 선언 + +> C 언어에서는 변수를 사용하기 전에 반드시 먼저 해당 변수를 저장하기 위한 메모리 공간을 할당받아야 한다. +> 이렇게 해당 변수만을 위한 메모리 공간을 할당받는 행위를 변수의 선언이라고 부른다. +> 만약 선언되지 않은 변수를 사용하려고 하면, C 컴파일러는 오류를 발생시킨다. + +> C 언어에서 변수를 선언하는 방법은 다음과 같이 두 가지 방법이 있다. + +1. 변수의 선언만 하는 방법 + +2. 변수의 선언과 동시에 초기화하는 방법 + +### 1.4.1 변수의 선언만 하는 방법 + +> 이 방법은 먼저 변수를 선언하여 메모리 공간만을 할당받고, +> 나중에 변수를 초기화하는 방법이다. + +> C 언어에서 변수를 선언하는 방법은 다음과 같다. + +- 문법 + +```c +타입 변수이름; +``` + +- 예제 + +```c +int num; + +... + +num = 20; +``` + +> 위의 예제처럼 정수를 저장하기 위한 메모리 공간을 할당받으면, +> 반드시 해당 타입의 데이터만을 저장해야 한다. +> 그렇지 않고 다른 타입의 데이터를 저장할 경우에는 +> 저장된 데이터에 변형 및 손실이 일어날 수도 있다. + +> 변수의 초기화란 해당 변수를 사용할 수 있도록 초기값을 설정하는 행위이다. +초기화되지 않은 변수에는 아무런 의미 없는 값인 쓰레깃값만이 들어가 있다. + +- 예제 + +```c +int num; +printf("%d", num); +``` + +> 위의 예제에서 변수 num은 선언만 하고 아직 초기화되지 않았다. +하지만 printf() 함수에서 변수 num을 사용하여 해당 변수에 저장된 값을 출력하려고 하고 있다. + +> 이와 같은 경우에 C 컴파일러는 오류를 발생시키지는 않겠지만, +> 프로그램은 사용자가 의도하지 않은 결과를 출력할 것이다. +> 따라서 C 언어에서는 초기화되지 않은 변수는 절대로 사용해서는 안된다. + +### 1.4.2 변수의 선언과 동시에 초기화하는 방법 + +> C언어에서 변수는 선언과 동시에 그 값을 초기화할 수 있다. +또한, 선언하고자 하는 변수들의 타입만 같다면 여러 변수를 동시에 선언할 수도 있다. + +- 문법 + +```c +1. 타입 변수이름[, 변수이름]; +2. 타입 변수이름 = 초깃값[, 변수이름 = 초깃값]; +``` + +- 예제 + +```c +int num01, num02; +double num03 = 1.23, num04 = 4.56; +``` + + \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-07_Constant.md b/_posts/Language/C/2023-12-03-07_Constant.md new file mode 100644 index 000000000000..23c210bac67a --- /dev/null +++ b/_posts/Language/C/2023-12-03-07_Constant.md @@ -0,0 +1,58 @@ +--- +layout: single +title: Chapter 07 상수 +date: 2023-12-03 11:57:05 +09:00 +categories: Language +tags: C +excerpt: 상수에 관한 글입니다. +toc: true +--- + +# 1 상수(constant) + +- 상수(constant) + +> 상수(constant)란 변수와 마찬가지로 데이터를 저장할 수 있는 메모리 공간을 의미한다. + +> 하지만 상수가 변수와 다른 점은 프로그램이 실행되는 동안 상수에 저장된 데이터는 변경할 수 없다는 점이다. + +> 이러한 상수는 표현 방식에 따라 다음과 같이 나눌 수 있다. + +1. 리터럴 상수(literal constant) + +2. 심볼릭 상수(symbolic constant) + +## 1.1 리터럴 상수(literal constant) + +> 리터럴 상수(literal constant)는 변수와는 달리 데이터가 저장된 메모리 공간을 가리키는 이름을 가지고 있지 않다. +> C 언어에서는 적절한 메모리 공간을 할당받기 위하여, +기본적으로 변수든 상수든 타입을 가지게 된다. + +> 리터럴 상수는 타입에 따라 정수형 리터럴 상수, 실수형 리터럴 상수, 문자형 리터럴 상수 등으로 구분할 수 있다. + +1. 정수형 리터럴 상수는 123, -456과 같이 아라비아 숫자와 부호로 직접 표현된다. + +2. 실수형 리터럴 상수는 3.14, -45.6과 같이 소수 부분을 가지는 아라비아 숫자로 표현된다. + +3. 문자형 리터럴 상수는 'a', 'Z'와 같이 따옴표('')로 감싸진 문자로 표현된다. + +- 예제 + +```c +123 // 정수형 리터럴 상수 +3.14 // 실수형 리터럴 상수 +'a' // 문자형 리터럴 상수 +``` + +## 1.2 심볼릭 상수(symbolic constant) + +> 심볼릭 상수는 변수와 마찬가지로 이름을 가지고 있는 상수이다. +이러한 심볼릭 상수는 반드시 선언과 동시에 초기화되어야 한다. +심볼릭 상수는 const 키워드를 사용하거나, 매크로를 이용하여 선언할 수 있다. + +- 예제 + +```c +const int MAX = 10; // const 키워드를 이용한 심볼릭 상수 +#define MAX 10; // #define 선행처리 지시자를 이용한 매크로 심볼릭 상수 +``` diff --git a/_posts/Language/C/2023-12-03-08_BasicType.md b/_posts/Language/C/2023-12-03-08_BasicType.md new file mode 100644 index 000000000000..16ccad294420 --- /dev/null +++ b/_posts/Language/C/2023-12-03-08_BasicType.md @@ -0,0 +1,173 @@ +--- +layout: single +title: Chapter 08 기본 타입 +date: 2023-12-03 11:57:38 +09:00 +categories: Language +tags: C +excerpt: 기본 타입에 관한 글입니다. +toc: true +--- + +# 1 기본 타입 + +- 타입(data type) + +> C 언어에서 타입(data type)이란 해당 데이터가 메모리에 어떻게 저장되고, +> 프로그램에서 어떻게 처리되어야 하는지를 명시적으로 알려주는 역할을 의미한다. + +> C 언어는 여러 형태의 타입을 미리 작성하여 제공하고 있는데, 이것을 기본 타입이라고 한다. +> 이러한 기본 타입은 크게 정수형, 실수형, 그리고 문자형 타입으로 나눌 수 있다. + +## 1.1 정수형 타입 + +- 정수 + +> C 언어에서 정수란 부호를 가지고 있고, 소수 부분이 없는 수를 의미한다. + +> 정수형 데이터에 unsigned 키워드를 추가하면, 부호를 나타내는 +최상위 비트(MSB, Most Significant Bit)까지도 크기를 나타내는 데 사용할 수 있다. + +> unsigned 정수는 음수를 표현할 수는 없게 되지만, +0을 포함한 양의 정수는 두 배 더 많이 표현할 수 있게 된다. + +> 음의 정수까지도 표현할 수 있는 signed 키워드는 +모든 타입에서 기본적으로 생략하여 사용할 수 있다. + +- 최상위 비트(MSB, Most Significant Bit) + +> 최상위 비트(MSB, Most Significant Bit)란 1바이트를 구성하는 8개의 비트 중 최고값을 갖는 비트를 의미한다. + +> 다음 표는 각각의 정수 타입에 따른 메모리의 크기 및 데이터의 표현 범위를 나타낸다. + +![](https://velog.velcdn.com/images/ecg/post/2762a0e4-ea8c-483f-a741-154f260591d3/image.png) + +> 정수형 데이터의 타입을 결정할 때에는 +> 반드시 자신이 사용하고자 하는 데이터의 최대 크기를 고려해야 한다. +해당 타입이 표현할 수 있는 범위를 벗어난 데이터를 저장하면, +오버플로우가 발생해 전혀 다른 값이 저장될 수 있기 때문이다. + +- 오버플로우(overflow) + +> 오버플로우(overflow)란 해당 타입이 표현할 수 있는 최대 범위보다 큰 수를 저장할 때 발생하는 현상을 의미한다. + +> 오버플로우가 발생하면 최상위 비트(MSB)를 벗어난 데이터가 인접 비트를 덮어쓰므로, 잘못된 결과를 얻을 수 있다. + +- 언더플로우(underflow) + +> 언더플로우(underflow)란 해당 타입이 표현할 수 있는 최소 범위보다 작은 수를 저장할 때 발생하는 현상을 의미한다. + +> 다음 예제는 int형 변수에 해당 타입이 저장할 수 있는 최댓값과 그 최댓값을 넘는 숫자를 대입하는 예제이다. + +- 예제 + +```c +int num = 2147483647; // int형 타입이 저장할 수 있는 최댓값인 2^31 - 1 +printf("변수 num에 저장된 값은 %d입니다.\n", num); + +num = 2147483648; // int형 타입이 저장할 수 없는 숫자인 2^31 +printf("변수 num에 저장된 값은 %d입니다.\n", num); +``` + +- 실행 결과 + +```c +변수 num에 저장된 값은 2147483647입니다. +변수 num에 저장된 값은 -2147483648입니다. +``` + +> 위의 두 번째 실행 결과를 살펴보면, +> 변수 num에 양수를 대입했지만 음수로 저장된 것을 확인할 수 있다. +이처럼 오버플로우가 발생하면 전혀 예상치 못한 결과를 얻을 수 있으므로, +데이터를 저장할 때는 언제나 해당 데이터 타입의 최대 크기까지 고려해야 한다. + +> 컴퓨터는 내부적으로 정수형 중에서도 int형의 데이터를 가장 빠르게 처리한다. +따라서 정수형 데이터는 보편적으로 크기에 상관없이 int형을 가장 많이 사용한다. +int형은 운영체제의 환경에 따라 다르다. +16bit라면 2바이트, 32bit라면 4바이트, 64bit이상부터 4바이트이다. + +## 1.2 실수형 타입 + +> C 언어에서 실수란 소수부나 지수가 있는 수를 가리키며, +> 정수보다 훨씬 더 넓은 표현 범위를 가진다. +하지만 컴퓨터에서 실수를 표현하는 방식은 반드시 오차가 발생하는 기술적 한계를 지닌다. +이러한 실수형 데이터의 오차는 C 언어뿐만 아니라 + 모든 프로그래밍 언어에서 발생하는 공통된 문제이다. + +![](https://velog.velcdn.com/images/ecg/post/416d2a6d-8a45-48e3-8967-74b248db8e35/image.png) + +> 다음 예제는 소수점을 16자리 가지는 실수를 float형과 double형 변수에 각각 대입하는 예제이다. + +- 예제 + +```c +float num01 = 3.1415926535897932; // float 타입의 유효 자릿수는 소수점 6자리 +printf("변수 pi에 저장된 값은 %.20f입니다.\n", num01); + +double num02 = 3.1415926535897932; // double 타입의 유효 자릿수는 소수점 16자리 +printf("변수 pi에 저장된 값은 %.20f입니다.\n", num02); +``` + +- 실행 결과 + +```c +변수 num01에 저장된 값은 3.14159274101257324219입니다. +변수 num02에 저장된 값은 3.14159265358979311600입니다. +``` + +> 위의 예제에서 변수 num01에는 소수점 6자리까지만 정확한 값이 저장되어 있고, +소수점 7자리부터는 틀린 값이 저장되어 있다. +또한, 변수 num02에는 소수점 15자리까지만 정확한 값이 저장되어 있고, +소수점 16자리부터는 틀린 값이 저장되어 있는 것을 확인할 수 있다. + +> 이처럼 실수형 데이터의 타입을 결정할 때는 표현 범위 이외에도 유효 자릿수를 반드시 고려해야 한다. + +![](https://velog.velcdn.com/images/ecg/post/eb3062c9-5630-4003-920e-f8c5ec6f5b8f/image.png) + +> 과거에는 실수를 표현할 때 float형을 많이 사용했지만, +> 하드웨어의 발달로 인한 메모리 공간의 증가로 현재에는 double형을 가장 많이 사용한다. + +## 1.3 문자형 타입 + +- 문자형 타입 + +>C 언어에서 문자형 타입이란 문자 하나를 표현할 수 있는 타입을 의미한다. + +> 컴퓨터는 2진수밖에 인식하지 못하므로, 문자도 숫자로 표현해야 컴퓨터가 인식할 수 있다. +따라서 어떤 문자를 어떤 숫자에 대응시킬 것인가에 대한 약속이 필요하다. + +> 이러한 약속 중에서 가장 많이 사용되는 것이 바로 아스키코드(ASCII)이다. + +- 아스키코드(ASCII) + +> 아스키코드(ASCII)란 영문 대소문자를 사용하는 7비트의 문자 인코딩 방식을 의미한다. + +> 아스키코드는 문자를 7비트로 표현하므로, 총 128개의 문자를 표현할 수 있다. + +> 아스키코드의 구성은 다음과 같다. + + - 출력할 수 없는 33개의 문자 + + - 출력할 수 있는 52개의 영문 대소문자, 10개의 숫자, 32개의 특수 문자와 1개의 공백 문자 + +![](https://velog.velcdn.com/images/ecg/post/d743ef3f-4a40-4e87-aeb0-5b84dda4b510/image.png) + +>다음 예제는 char형 변수에 저장된 문자를 여러 서식 지정자를 사용하여 출력하는 예제이다. + +- 예제 + +```c +char ch = 'a'; +printf("변수 ch에 저장된 값은 %c입니다.\n", ch); +printf("변수 ch에 저장된 값은 %d입니다.\n", ch); +``` + +- 실행 결과 + +```c +변수 ch에 저장된 값은 a입니다. +변수 ch에 저장된 값은 97입니다. +``` + +> 위의 예제에서 서식 지정자 '%c'를 사용하여 출력한 결과는 제대로 문자 'a'가 출력된다. +하지만 서식 지정자 '%d'를 사용하여 출력한 결과는 97이라는 숫자로 출력된다. +즉, 이것은 문자가 내부적으로는 아스키코드에 해당하는 숫자로 저장되어 있음을 보여준다. diff --git a/_posts/Language/C/2023-12-03-09_TypeCasting.md b/_posts/Language/C/2023-12-03-09_TypeCasting.md new file mode 100644 index 000000000000..cf0bb22a0c41 --- /dev/null +++ b/_posts/Language/C/2023-12-03-09_TypeCasting.md @@ -0,0 +1,138 @@ +--- +layout: single +title: Chapter 09 타입 변환 +date: 2023-12-03 11:57:46 +09:00 +categories: Language +tags: C +excerpt: 타입 변환에 관한 글입니다. +toc: true +--- + +# 1 타입 변환(type conversion) + +> C 언어에서 다른 타입끼리의 연산은 우선 피연산자들을 모두 같은 타입으로 만든 후에 수행된다. + +- 타입 변환(type conversion) + +>타입 변환(type conversion)이란 하나의 타입을 다른 타입으로 바꾸는 행위를 의미한다. + +> 표현 범위가 좁은 타입에서 표현 범위가 +> 더 넓은 타입으로의 타입 변환은 큰 문제가 되지 않는다. +하지만 반대의 경우인 표현 범위가 좁은 타입으로의 타입 변환에서는 +데이터의 손실이 발생한다. + +> 타입 변환은 크게 다음과 같이 두 가지 방식으로 나눌 수 있다. + +1. 묵시적 타입 변환(자동 타입 변환) + +2. 명시적 타입 변환(강제 타입 변환) + +## 1.1 묵시적 타입 변환(자동 타입 변환, implicit type conversion) + +- 묵시적 타입 변환 + +> 묵시적 타입 변환이란 대입 연산이나 산술 연산에서 +C 컴파일러가 자동으로 실행해주는 타입 변환을 의미한다. + +> C 언어에서는 대입 연산 시 연산자의 오른쪽에 존재하는 데이터의 타입이 +연산자의 왼쪽에 존재하는 데이터의 타입으로 묵시적 타입 변환이 진행된다. +또한, 산술 연산에서는 데이터의 손실이 최소화되는 방향으로 묵시적 타입 변환이 진행된다. + +> 다음 예제는 대입 연산에서 일어나는 묵시적 타입 변환을 보여준다. + +- 예제 + +```c +char ch = 200; +int num01 = 3.14; +double num02 = 5; + +printf(" ch에 저장된 값은 %d입니다.\n", ch); +printf("num01에 저장된 값은 %d입니다.\n", num01); +printf("num02에 저장된 값은 %f입니다.\n", num02); +``` + +- 실행 결과 + +```c + ch에 저장된 값은 -56입니다. +num01에 저장된 값은 3입니다. +num02에 저장된 값은 5.000000입니다. +``` + +> 위의 예제에서는 char형 변수에 char형 변수가 표현할 수 있는 범위를 넘는 데이터를 저장한다. +따라서 전달된 데이터의 상위 비트가 자동으로 삭제되어 데이터의 손실이 발생한다. +또한, int형 변수에 실수를 저장했기 때문에 +소수 부분이 자동으로 삭제되어 데이터의 손실이 발생한다. +하지만 double형 변수에 int형 데이터를 저장하는 것은 +데이터가 double형으로 자동 타입 변환되지만, +데이터의 손실은 발생하지 않는다. + +> 다음 예제는 산술 연산에서 일어나는 묵시적 타입 변환을 보여준다. + +- 예제 + +```c +double result01 = 5 + 3.14; +double result02 = 5.0f + 3.14; + +printf("result01에 저장된 값은 %f입니다.\n", result01); +printf("result02에 저장된 값은 %f입니다.\n", result02); + +``` +- 실행 결과 + +```c +result01에 저장된 값은 8.140000입니다. +result02에 저장된 값은 8.140000입니다. +``` + +> 위의 예제에서 첫 번째 연산은 int형 데이터와 double형 데이터의 산술 연산이다. +따라서 데이터의 손실이 최소화되도록 int형 데이터가 double형 데이터로 자동 타입 변환된다. +두 번째 연산은 float형 데이터와 double형 데이터의 산술 연산이다. +위와 마찬가지로 데이터의 손실이 최소화되도록 +float형 데이터가 double형 데이터로 자동 타입 변환된다. + +> 이렇게 컴파일러가 자동으로 수행하는 타입 변환은 +언제나 데이터의 손실이 최소화되는 방향으로 이루어진다. +따라서 C 컴파일러는 다음과 같은 순서대로 자동 타입 변환을 수행하게 된다. + +> char 형 → short 형 → int 형 → long 형 → float 형 → double 형 → long double 형 + +## 1.2 명시적 타입 변환(강제 타입 변환, explicit type conversion) + +- 명시적 타입 변환 + +> 명시적 타입 변환이란 사용자가 타입 캐스트(type cast) 연산자를 사용하여 +> 강제적으로 수행하는 타입 변환을 의미한다. + +> 변환하고자 하는 데이터의 앞에 괄호(())를 추가하고, 그 안에 변환할 타입을 적으면 된다. +C언어에서는 이 괄호(())를 타입 캐스트(type cast) 연산자라고 한다. + +> 다음 예제는 명시적 타입 변환을 보여주는 예제이다. + +- 예제 + +```c +int num01 = 1; +int num02 = 4; + +double result01 = num01 / num02; +double result02 = (double)num01 / num02; + +printf("result01에 저장된 값은 %f입니다.\n", result01); +printf("result02에 저장된 값은 %f입니다.\n", result02); +``` + +- 실행 결과 + +```c +result01에 저장된 값은 0.000000입니다. +result02에 저장된 값은 0.250000입니다. +``` + +> 위의 예제에서 첫 번째 연산의 결괏값은 0.000000으로 출력된다. +그 이유는 산술 연산에 대한 결괏값의 타입은 피연산자의 타입과 언제나 일치하기 때문이다. +즉, int형 데이터끼리의 산술 연산에 대한 결괏값은 언제나 int형 데이터로 나온다. +따라서 두 번째 연산에서처럼 하나의 피연산자를 명시적으로 +double형으로 지정해야만 정확한 결괏값을 얻을 수 있다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-10_ArithmeticOperator.md b/_posts/Language/C/2023-12-03-10_ArithmeticOperator.md new file mode 100644 index 000000000000..43e195b1c152 --- /dev/null +++ b/_posts/Language/C/2023-12-03-10_ArithmeticOperator.md @@ -0,0 +1,98 @@ +--- +layout: single +title: Chapter 10 산술 연산자 +date: 2023-12-03 11:58:02 +09:00 +categories: Language +tags: C +excerpt: 산술 연산자에 관한 글입니다. +toc: true +--- + +# 1 연산자(operator) + +- 연산자(operator) + +> 연산자(operator)란 프로그램의 산술식이나 연산식을 +표현하고 처리하기 위해 제공되는 다양한 기호를 의미한다. + +> C 언어에서는 여러 종류의 연산을 위해 다양한 연산자를 제공하고 있다. + +## 1.1 산술 연산자(arithmetic operator) + +- 산술 연산자(arithmetic operator) + +> 산술 연산자(arithmetic operator)란 사칙연산을 다루는 기본적이면서도 가장 많이 사용되는 연산자를 의미한다. + +> 산술 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, +피연산자들의 결합 방향은 왼쪽에서 오른쪽이다. + +- 항 + +> 항이란 해당 연산의 실행이 가능하기 위해 필요한 값이나 변수를 의미한다. +따라서 이항 연산자란 해당 연산의 실행을 위해서 +두 개의 값이나 변수가 필요한 연산자를 의미한다. + +![](https://velog.velcdn.com/images/ecg/post/8e54c925-26b2-400a-b914-a5dd0280d238/image.png) + +- 예제 + +```c +int num01 = 10; +int num02 = 4; + +printf("+ 연산자에 의한 결괏값은 %d입니다.\n", num01 + num02); +printf("- 연산자에 의한 결괏값은 %d입니다.\n", num01 - num02); +printf("* 연산자에 의한 결괏값은 %d입니다.\n", num01 * num02); +printf("/ 연산자에 의한 결괏값은 %d입니다.\n", num01 / num02); +printf("% 연산자에 의한 결괏값은 %d입니다.\n", num01 % num02); +``` + +- 실행 결과 + +```c ++ 연산자에 의한 결괏값은 14입니다. +- 연산자에 의한 결괏값은 6입니다. +* 연산자에 의한 결괏값은 40입니다. +/ 연산자에 의한 결괏값은 2입니다. +% 연산자에 의한 결괏값은 2입니다. +``` + +## 1.2 연산자의 우선순위(operator precedence)와 결합 방향(associativity) + +> 연산자의 우선순위는 수식 내에 여러 연산자가 함께 등장할 때, +어느 연산자가 먼저 처리될 것인가를 결정한다. + +> 다음 그림은 가장 높은 우선순위를 가지고 있는 +괄호(()) 연산자를 사용하여 연산자의 처리 순서를 변경하는 것을 보여준다. + +![](https://velog.velcdn.com/images/ecg/post/a43c5d73-8507-4abb-bc7c-749e8bbcc0d6/image.png) + +> 연산자의 결합 방향은 수식 내에 우선순위가 같은 연산자가 둘 이상 있을 때, +먼저 어느 연산을 수행할 것인가를 결정한다. + +![](https://velog.velcdn.com/images/ecg/post/480e8a55-87ff-484a-9b39-384f0364c058/image.png) + +## 1.3 C 언어 연산자의 우선순위 + +> C 언어에서 연산자의 우선순위와 결합 방향은 다음과 같다. + +- 1순위 + +![](https://velog.velcdn.com/images/ecg/post/2ec55668-2e92-435d-aa01-dac622419564/image.png) + +- 2순위 + +![](https://velog.velcdn.com/images/ecg/post/1d9517d0-4cfb-42ed-aaa6-e8addbecf2ba/image.png) + +- 3 ~ 7 순위 + +![](https://velog.velcdn.com/images/ecg/post/9e035a21-123c-4858-9ace-a9d5cc1198c1/image.png) + +- 8 ~ 15 순위 + +![](https://velog.velcdn.com/images/ecg/post/3f43f584-f53a-4a89-998f-f4477d4a79c6/image.png) + +> 위의 표에서 나온 순서대로 우선순위가 빠른 연산자가 가장 먼저 실행된다. +또한, 같은 우선순위를 가지는 연산자가 둘 이상 있을 때에는 +결합 순서에 따라 실행 순서가 결정된다. + diff --git a/_posts/Language/C/2023-12-03-11_AssignmentOperator.md b/_posts/Language/C/2023-12-03-11_AssignmentOperator.md new file mode 100644 index 000000000000..02ccd8489eed --- /dev/null +++ b/_posts/Language/C/2023-12-03-11_AssignmentOperator.md @@ -0,0 +1,47 @@ +--- +layout: single +title: Chapter 11 대입 연산자 +date: 2023-12-03 11:58:07 +09:00 +categories: Language +tags: C +excerpt: 대입 연산자에 관한 글입니다. +toc: true +--- + +# 1 대입 연산자(assignment operator) + +- 대입 연산자(assignment operator) + +> 대입 연산자(assignment operator)란 변수에 값을 대입할 때 사용하는 이항 연산자를 의미한다. + +> 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다. +또한, 산술 연산자와 결합한 다양한 복합 대입 연산자가 존재한다. + +![](https://velog.velcdn.com/images/ecg/post/261fda28-96ee-4f71-9bf9-5c9695e2ab99/image.png) + +- 예제 + +```c +int num01 = 7; +int num02 = 7; +int num03 = 7; + +num01 = num01 - 5; +num02 -= 5; +num03 =- 5; + +printf("- 연산자에 의한 결괏값은 %d입니다.\n", num01); +printf("-= 연산자에 의한 결괏값은 %d입니다.\n", num02); +printf("=- 연산자에 의한 결괏값은 %d입니다.\n", num03); +``` + +- 실행 결과 + +```c +- 연산자에 의한 결괏값은 2입니다. +-= 연산자에 의한 결괏값은 2입니다. +=- 연산자에 의한 결괏값은 -5입니다. +``` + +> 위의 예제에서 num03 =- 5 연산은 단순히 -5를 변수 num03에 대입(=)하는 연산이 되었다. +이처럼 복합 대입 연산자에서 연산자의 순서는 매우 중요하다. diff --git a/_posts/Language/C/2023-12-03-12_IncrementAndDecrementOperator.md b/_posts/Language/C/2023-12-03-12_IncrementAndDecrementOperator.md new file mode 100644 index 000000000000..ff7d2c548bf3 --- /dev/null +++ b/_posts/Language/C/2023-12-03-12_IncrementAndDecrementOperator.md @@ -0,0 +1,86 @@ +--- +layout: single +title: Chapter 12 증감 연산자 +date: 2023-12-03 11:58:18 +09:00 +categories: Language +tags: C +excerpt: 증감 연산자에 관한 글입니다. +toc: true +--- + +# 1 증감 연산자(increment and decrement operator) + +- 증감 연산자(increment and decrement operator) + +> 증감 연산자(increment and decrement operator)란 +> 피연산자를 1씩 증가 혹은 1씩 감소시킬 때 사용하는 연산자를 의미한다. + +> 이 연산자는 피연산자가 단 하나뿐인 단항 연산자이다. + +> 증감 연산자는 해당 연산자가 피연산자의 어느 쪽에 +위치하는가에 따라 연산의 순서 및 결과가 달라진다. + +![](https://velog.velcdn.com/images/ecg/post/76c0c662-330b-43cb-9c15-5f7957b888ef/image.png) + +- 예제 + +```c +int num01 = 7; +int num02 = 7; +int result01, result02; + +result01 = (++num01) - 5; +result02 = (num02++) - 5; + +printf("전위 증가 연산자에 의한 결괏값은 %d이고, 변수의 값은 %d로 변했습니다.\n", result01, num01); +printf("후위 증가 연산자에 의한 결괏값은 %d이고, 변수의 값은 %d로 변했습니다.\n", result02, num02); +``` + +- 실행 결과 + +```c +전위 증가 연산자에 의한 결괏값은 3이고, 변수의 값은 8로 변했습니다. +후위 증가 연산자에 의한 결괏값은 2이고, 변수의 값은 8로 변했습니다. +``` + +> 위의 예제에서 첫 번째 연산은 변수 num01의 값을 먼저 1 증가시킨 후에 나머지 연산을 수행한다. +하지만 두 번째 연산에서는 먼저 모든 연산을 마친 후에 변수 num02의 값을 1 증가시킨다. +따라서 변수 num02의 증가는 관련된 연산에 아무런 영향도 미치지 않는다. + +## 1.1 증감 연산자의 연산 순서 + +> 증감 연산자는 피연산자의 어느 쪽에 위치하는가에 따라 연산의 순서가 달라진다. + +> 다음 예제는 증감 연산자의 연산 순서를 살펴보기 위한 예제이다. + +- 예제 + +```c +int x = 10; +int y = x-- + 5 + --x; + +printf("변수 x의 값은 %d이고, 변수 y의 값은 %d입니다.\n", x, y); +``` + +- 실행 결과 + +```c +변수 x의 값은 8이고, 변수 y의 값은 23입니다. +``` + +> 다음 그림은 위의 예제에서 수행되는 연산의 순서를 보여준다. + +![](https://velog.velcdn.com/images/ecg/post/657bb35d-f99c-44d6-b90f-8bc2fba1efb3/image.png) + +① : 첫 번째 감소 연산자(decrement operator)는 피연산자의 뒤쪽에 위치하므로, +덧셈 연산이 먼저 수행된다. + +② : 덧셈 연산이 수행된 후에 감소 연산이 수행된다. (x의 값 : 9) + +③ : 두 번째 감소 연산자는 피연산자의 앞쪽에 위치하므로, 덧셈 연산보다 먼저 수행된다. (x의 값 : 8) + +④ : 감소 연산이 수행된 후에 덧셈 연산이 수행된다. + +⑤ : 마지막으로 변수 y에 결괏값의 대입 연산이 수행된다. (y의 값 : 23) + + diff --git a/_posts/Language/C/2023-12-03-13_ComparisonOperator.md b/_posts/Language/C/2023-12-03-13_ComparisonOperator.md new file mode 100644 index 000000000000..0e856b7f4490 --- /dev/null +++ b/_posts/Language/C/2023-12-03-13_ComparisonOperator.md @@ -0,0 +1,41 @@ +--- +layout: single +title: Chapter 13 비교 연산자 +date: 2023-12-03 11:58:29 +09:00 +categories: Language +tags: C +excerpt: 비교 연산자에 관한 글입니다. +toc: true +--- + +# 1 비교 연산자(comparison operator) + +- 비교 연산자(comparison operator) + +> 비교 연산자(comparison operator)란 피연산자 사이의 상대적인 크기를 판단하는 연산자를 의미한다. + +> 비교 연산자는 왼쪽의 피연산자와 오른쪽의 피연산자를 비교하여, +어느 쪽이 더 큰지, 작은지, 또는 서로 같은지를 판단한다. +> 비교 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, +피연산자들의 결합 방향은 왼쪽에서 오른쪽이다. + +![](https://velog.velcdn.com/images/ecg/post/6f4f904d-d9d2-4c49-8e0a-e44d39a726ba/image.png) + +> C 언어에서 거짓(false)은 0이며, 0이 아닌 모든 것은 참(true)으로 인식된다. + +- 예제 + +```c +int num01 = 3; +int num02 = 7; + +printf("== 연산자에 의한 결괏값은 %d입니다.\n", num01 == num02); +printf("<= 연산자에 의한 결괏값은 %d입니다.\n", num01 <= num02); +``` + +- 실행 결과 + +```c +== 연산자에 의한 결괏값은 0입니다. +<= 연산자에 의한 결괏값은 1입니다. +``` diff --git a/_posts/Language/C/2023-12-03-14_LogicalOperator.md b/_posts/Language/C/2023-12-03-14_LogicalOperator.md new file mode 100644 index 000000000000..3d6c5d404af1 --- /dev/null +++ b/_posts/Language/C/2023-12-03-14_LogicalOperator.md @@ -0,0 +1,55 @@ +--- +layout: single +title: Chapter 14 논리 연산자 +date: 2023-12-03 11:58:35 +09:00 +categories: Language +tags: C +excerpt: 논리 연산자에 관한 글입니다. +toc: true +--- + +# 1 논리 연산자(logical operator) + +- 논리 연산자(logical operator) + +> 논리 연산자(logical operator)란 주어진 논리식을 판단하여, 참(true)과 거짓(false)을 결정하는 연산자를 의미한다. + +> AND 연산과 OR 연산은 두 개의 피연산자를 가지는 이항 연산자이며, +피연산자들의 결합 방향은 왼쪽에서 오른쪽이다. +NOT 연산자는 피연산자가 단 하나뿐인 단항 연산자이며, +피연산자의 결합 방향은 오른쪽에서 왼쪽이다. + +![](https://velog.velcdn.com/images/ecg/post/4a5a994c-e71e-4366-a9bc-4febee2b452a/image.png) + +> C언어에서 거짓(false)은 0이며, 0이 아닌 모든 것은 참(true)으로 인식된다. + +> 다음은 논리 연산자의 모든 동작의 결과를 보여주는 진리표(truth table)이다. + +![](https://velog.velcdn.com/images/ecg/post/4111ff52-cf54-4b52-8edb-159ad319ec0d/image.png) + +- 예제 + +```c +int num01 = 3; +int num02 = -7; +int result01, result02; + +result01 = (num01 > 0) && (num01 < 5); +result02 = (num02 < 0) || (num02 > 10); + +printf("&& 연산자에 의한 결괏값은 %d입니다.\n", result01); +printf("|| 연산자에 의한 결괏값은 %d입니다.\n", result02); +printf(" ! 연산자에 의한 결괏값은 %d입니다.\n", !result02); +``` + +- 실행 결과 + +```c +&& 연산자에 의한 결괏값은 1입니다. +|| 연산자에 의한 결괏값은 1입니다. + ! 연산자에 의한 결괏값은 0입니다. +``` + +> 컴퓨터에서 참(true)은 보통 1로 표현되고, 거짓(false)은 0으로 표현된다. +하지만 C언어에서는 음수를 포함해 0이 아닌 모든 수가 참(true)으로 취급된다. + diff --git a/_posts/Language/C/2023-12-03-15_BitwiseOperator.md b/_posts/Language/C/2023-12-03-15_BitwiseOperator.md new file mode 100644 index 000000000000..e1a0dc806905 --- /dev/null +++ b/_posts/Language/C/2023-12-03-15_BitwiseOperator.md @@ -0,0 +1,62 @@ +--- +layout: single +title: Chapter 15 비트 연산자 +date: 2023-12-03 11:58:45 +09:00 +categories: Language +tags: C +excerpt: 비트 연산자에 관한 글입니다. +toc: true +--- + +# 1 비트 연산자(bitwise operator) + +- 비트 연산자(bitwise operator) + +> 비트 연산자(bitwise operator)란 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산자를 의미한다. + +> 또한, 비트 단위로 전체 비트를 왼쪽이나 오른쪽으로 이동시킬 때도 사용한다. + +![](https://velog.velcdn.com/images/ecg/post/24c86468-2b2d-41c5-b9c1-5584c59d6ee8/image.png) + +> 다음 그림은 비트 AND 연산자(&)의 동작을 나타낸다. +이처럼 비트 AND 연산자는 대응되는 두 비트가 모두 1일 때만 1을 반환하며, +다른 경우는 모두 0을 반환한다. + +![](https://velog.velcdn.com/images/ecg/post/7cec40d3-b84a-4eb5-81b7-a547f59ea2b4/image.png) + +> 다음 그림은 비트 OR 연산자(|)의 동작을 나타낸다. +이처럼 비트 OR 연산자는 대응되는 두 비트 중 하나라도 1이면 1을 반환하며, +두 비트가 모두 0일 때만 0을 반환한다. + +![](https://velog.velcdn.com/images/ecg/post/8fdf9f18-94e6-48c4-b69a-b50d65b2fe5d/image.png) + +> 다음 그림은 비트 XOR 연산자(^)의 동작을 나타낸다. +이처럼 비트 XOR 연산자는 대응되는 두 비트가 서로 다르면 1을 반환하고, +서로 같으면 0을 반환한다. + +![](https://velog.velcdn.com/images/ecg/post/b18082b3-eeff-4b4a-8c28-8cf88e9ce27f/image.png) + +> 다음 그림은 비트 NOT 연산자(~)의 동작을 나타낸다. +이처럼 비트 NOT 연산자는 해당 비트가 1이면 0을 반환하고, 0이면 1을 반환한다. + +![](https://velog.velcdn.com/images/ecg/post/8872793a-1d5b-4bb6-8bd5-413460192262/image.png) + +> 다음 예제는 비트 NOT 연산자(~)와 시프트 연산자(<<, >>)의 예제이다. + +- 예제 + +```c +int num01 = 15; int num02 = 8; + +printf(" ~ 연산자에 의한 결괏값은 %d입니다.\n", ~num01); // 1의 보수 +printf("<< 연산자에 의한 결괏값은 %d입니다.\n", num02 << 1); // 곱하기 2 +printf(">> 연산자에 의한 결괏값은 %d입니다.\n", num02 >> 1); // 나누기 2 +``` + +- 실행 결과 + +```c + ~ 연산자에 의한 결괏값은 -16입니다. +<< 연산자에 의한 결괏값은 16입니다. +>> 연산자에 의한 결괏값은 4입니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-16_OtherOperator.md b/_posts/Language/C/2023-12-03-16_OtherOperator.md new file mode 100644 index 000000000000..4c5a7b3bd2c8 --- /dev/null +++ b/_posts/Language/C/2023-12-03-16_OtherOperator.md @@ -0,0 +1,119 @@ +--- +layout: single +title: Chapter 16 기타 연산자 +date: 2023-12-03 11:58:52 +09:00 +categories: Language +tags: C +excerpt: 기타 연산자에 관한 글입니다. +toc: true +--- + +# 1 삼항 연산자(ternary operator) + +- 삼항 연산자(ternary operator) + +> 삼항 연산자(ternary operator)란 C 언어에서 유일하게 피연산자를 세 개나 가지는 조건 연산자를 의미한다. + +> 삼항 연산자의 문법은 다음과 같다. + +- 문법 + +```c +조건식 ? 반환값1 : 반환값2 +``` + +> 물음표(?) 앞의 조건식에 따라 결괏값이 참(true)이면 반환값1을 반환하고, +결괏값이 거짓(false)이면 반환값2를 반환된다. +이때 반환값에는 값뿐만 아니라 수식, 함수 호출 등 +여러 가지 형태의 명령문이 올 수 있다. + +- 예제 + +```c +int num01 = 15; +int num02 = 8; +int result; + +result = (num01 > num02) ? num01 : num02; +printf("둘 중에 더 큰수는 %d입니다.\n", result); +``` + +- 실행 결과 + +> 둘 중에 더 큰수는 15이다. + +> 삼항 연산자는 짧은 if / else 문 대신에 사용할 수 있으며, +코드를 간결하게 작성할 수 있도록 도와준다. + +# 2 쉼표 연산자 + +- 쉼표 연산자 + +> 쉼표(,) 연산자란 얼핏 연산자가 아닌 것처럼 보이지만 다양한 용도로 사용되는 연산자를 의미한다. +> 이 연산자는 어떠한 연산을 수행하는 것이 아니라 다음과 같은 상황에서 사용된다. + + 1. 두 연산식을 하나의 연산식으로 나타내고자 할 때 + + 2. 둘 이상의 인수를 함수로 전달하고자 할 때 + +- 예제 + +```c +int num01 = 15, num02 = 8; +printf("첫 번째 수는 %d이고, 두 번째 수는 %d입니다.\n", num01, num02); +``` + +- 실행 결과 + +```c +첫 번째 수는 15이고, 두 번째 수는 8입니다. +``` + +> 위의 예제에서 쉼표 연산자는 둘 이상의 변수를 동시에 선언하기 위해서 사용되었다. +또한, printf() 함수에서는 둘 이상의 인수를 동시에 printf() 함수로 전달하기 위해서 사용되었다. + +# 3 sizeof 연산자 + +> 사용자의 컴퓨터 환경에 따라 타입에 할당되는 메모리의 크기가 달라질 수 있다. +sizeof 연산자는 단항 연산자로 피연산자의 크기를 바이트 단위로 반환한다. +이 연산자는 피연산자로 타입뿐만 아니라 변수나 상수를 전달받을 수도 있다. +sizeof 연산자에 변수나 상수가 피연산자로 전달되면, +해당 변수나 상수에 해당하는 타입의 크기를 반환해 준다. + +- 예제 + +```c +printf("char: %d, short: %d, int: %d, long: %d, long long: %d\n", + sizeof(char), // 1: sizeof로 char 자료형의 크기를 구함 + sizeof(short), // 2: sizeof로 short 자료형의 크기를 구함 + sizeof(int), // 4: sizeof로 int 자료형의 크기를 구함 + sizeof(long), // 4: sizeof로 long 자료형의 크기를 구함 + sizeof(long long) // 8: sizeof로 long long 자료형의 크기를 구함 +); +``` + +- 실행 결과 + +```c +char: 1, short: 2, int: 4, long: 4, long long: 8 +``` + +> sizeof 연산자를 통해 컴퓨터 환경에서의 타입 크기를 알아볼 수 있다. + +# 4 포인터 연산자 + +> C 언어에서 포인터와 연관되어 사용되는 연산자는 다음과 같다. + +1. 주소 연산자(&) + +2. 참조 연산자(*) + +> 주소 연산자(&)는 변수의 이름 앞에 사용하여, 해당 변수의 주소값을 반환한다. +'&'기호는 앰퍼샌드(ampersand)라고 읽으며, 번지 연산자라고도 불린다. + +> 참조 연산자(*)는 포인터의 이름이나 주소 앞에 사용하여, +포인터에 가리키는 주소에 저장된 값을 반환한다. + +> C 언어에서 '*'기호는 사용하는 위치에 따라 다양한 용도로 사용된다. +> 이항 연산자로 사용하면 곱셈 연산으로 사용되며, +포인터의 선언 시나 메모리에 접근할 때도 사용된다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-17_ConditionalStatement.md b/_posts/Language/C/2023-12-03-17_ConditionalStatement.md new file mode 100644 index 000000000000..9196bbceef3d --- /dev/null +++ b/_posts/Language/C/2023-12-03-17_ConditionalStatement.md @@ -0,0 +1,376 @@ +--- +layout: single +title: Chapter 17 조건문 +date: 2023-12-03 11:59:00 +09:00 +categories: Language +tags: C +excerpt: 조건문에 관한 글입니다. +toc: true +--- + +# 1 제어문(control flow statements) + +> C 프로그램은 절차적 프로그램(procedural program) +또는 명령형 프로그램(Imperative program)에 속한다. +C 프로그램에는 수많은 명령문이 포함되어 있으며, +이 명령문은 처음부터 끝까지 순서대로 실행된다. +따라서 원하는 결과를 얻기 위해서는 프로그램의 +이러한 순차적인 흐름을 제어해야만 한다. + +> 이때 사용하는 명령문을 제어문이라고 하며, +제어문에는 조건문, 반복문 등이 있다. +제어문에 속하는 명령문들은 중괄호({})로 둘러싸여 있으며, +이러한 중괄호 영역을 블록(block)이라고 한다. + +## 1.1 조건문(conditional statements) + +- 조건문(conditional statements) + +> 조건문(conditional statements)이란 주어진 조건식의 결과에 따라 별도의 명령을 수행하도록 제어하는 명령문을 의미한다. + +> 조건문 중에서도 가장 기본이 되는 명령문은 바로 if 문이다. + +> C 언어에서 사용하는 대표적인 조건문의 형태는 다음과 같다. + +1. if 문 +2. if / else 문 +3. if / else if / else 문 +4. switch 문 + +## 1.2 if 문 + +> if 문은 조건식의 결과가 참(true)이면 주어진 명령문을 실행하며, +> 거짓(false)이면 아무것도 실행하지 않는다. + +> if 문을 순서도로 표현하면 다음 그림과 같다. + +![](https://velog.velcdn.com/images/ecg/post/aea7be98-1092-4d6d-9ff5-579a6c48402a/image.png) + +> C 언어에서 if 문의 문법은 다음과 같다. + +- 문법 + +```c +if (조건식) +{ + 조건식의 결과가 참일 때 실행하고자 하는 명령문; +} +``` + +> 위의 코드에서 블록에 속한 명령문은 중괄호({})를 기준으로 +오른쪽으로 들여쓰기가 되어 있는 것을 볼 수 있다. + +- 인덴트(indent) + +>인덴트(indent)란 들여쓰기를 통해 코드의 가독성을 높이는 것을 의미한다. + +>될 수 있으면 모든 코드를 인덴트하는 것이 좋다. + +> 다음 예제는 if 문을 3번 연속해서 사용하여, +사용자가 입력한 수와 숫자 5를 비교하여 그 결괏값을 출력하는 예제이다. + +- 예제 + +```c +int num = 3; +if (num < 5) +{ + printf("입력하신 수는 5보다 작습니다.\n"); +} +if (num == 5) +{ + printf("입력하신 수는 5입니다.\n"); +} +if (num > 5) +{ + printf("입력하신 수는 5보다 큽니다.\n"); +} +``` + +- 실행 결과 + +```c +입력하신 수는 5보다 작습니다. +``` + +> if 문에서 실행될 명령문이 한 줄 뿐이라면 중괄호({})를 생략할 수 있다. + +## 1.3 if / else 문 + +> if 문과 함께 사용하는 else 문은 if 문과는 반대로 주어진 조건식의 결과가 거짓(false)이면 주어진 명령문을 실행한다. + +> if / else 문을 순서도로 표현하면 다음 그림과 같다. + +![](https://velog.velcdn.com/images/ecg/post/11fb4a60-2789-4e3d-b352-d290c1e6f185/image.png) + +> C 언어에서 else 문의 문법은 다음과 같다. + +- 문법 + +```c +if (조건식) +{ + 조건식의 결과가 참일 때 실행하고자 하는 명령문; +} +else +{ + 조건식의 결과가 거짓일 때 실행하고자 하는 명령문; +} +``` + +> else 문을 사용하면 좀 더 직관적으로 표현할 수 있다. + +- 예제 + +```c +int num = 5; +if (num < 5) +{ + printf("입력하신 수는 5보다 작습니다.\n"); +} +else +{ + if (num == 5) + { + printf("입력하신 수는 5입니다.\n"); + } + else + { + printf("입력하신 수는 5보다 큽니다.\n"); + } +} +``` + +- 실행 결과 + +```c +입력하신 수는 5입니다. +``` + +> else 문에서도 실행될 명령문이 한 줄뿐이라면 중괄호({})를 생략할 수 있다. + +## 1.4 if / else if / else 문 + +> else if 문은 if 문처럼 조건식을 가질 수 있기 때문에 +중첩된 if 문을 좀 더 간결하게 표현할 수 있도록 해준다. +하나의 조건문 안에서 if 문과 else 문은 단 한 번만 사용될 수 있다. +하지만 else if 문은 여러 번 사용될 수 있어서 +복잡한 조건도 표현할 수 있다. + +> if / else if / else 문을 순서도로 표현하면 다음 그림과 같다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/03bc8c46-94bd-461c-8032-a2a0e0b58c6d) + +> C 언어에서 else if 문의 문법은 다음과 같다. + +- 문법 + +``` +if (조건식1) +{ + 조건식1의 결과가 참일 때 실행하고자 하는 명령문; +} +else if (조건식2) +{ + 조건식2의 결과가 참일 때 실행하고자 하는 명령문; +} +else +{ + 조건식1의 결과도 거짓이고, 조건식2의 결과도 거짓일 때 실행하고자 하는 명령문; +} +``` + +> else if 문을 사용하면 더욱 간결하게 표현할 수 있다. + +- 예제 + +```c +int num = 7; +if (num < 5) +{ + printf("입력하신 수는 5보다 작습니다.\n"); +} +else if (num == 5) +{ + printf("입력하신 수는 5입니다.\n"); +} +else +{ + printf("입력하신 수는 5보다 큽니다.\n"); +} +``` + +- 실행 결과 + +```c +입력하신 수는 5보다 큽니다. +``` + +> else if 문에서도 실행될 명령문이 한 줄뿐이라면 중괄호({})를 생략할 수 있다. + +## 1.5 삼항 연산자에 의한 조건문 + +> C 언어에서는 if / else 문을 삼항 연산자를 이용하여 간단히 표현할 수 있다. + +- 문법 + +```c +조건식 ? 반환값1 : 반환값2 +``` + +## 1.6 switch 문 + +> switch 문은 if / else 문과 마찬가지로 주어진 조건 값의 결과에 따라 +> 프로그램이 다른 명령을 수행하도록 하는 조건문이다. +이러한 switch 문은 if / else 문보다 가독성이 더 좋으며, +컴파일러가 최적화를 쉽게 할 수 있어 속도 또한 빠른 편이다. + +> 하지만 switch 문의 조건 값으로는 int형으로 +> 승격할 수 있는(integer promotion) 값만이 사용될 수 있다. +즉, C 언어에서는 char형, short형, int형 변수나 +리터럴과 열거체까지 사용할 수 있다. +따라서 if / else 문보다는 사용할 수 있는 상황이 적은 편이다. + +> C 언어에서 switch 문의 문법은 다음과 같다. + +- 문법 + +```c +switch (조건 값) +{ + case 값1: + 조건 값이 값1일 때 실행하고자 하는 명령문; + break; + case 값2: + 조건 값이 값2일 때 실행하고자 하는 명령문; + break; + ... + default: + 조건 값이 어떠한 case 절에도 해당하지 않을 때 실행하고자 하는 명령문; + break; +} +``` + +> default 절은 조건 값이 위에 나열된 +어떠한 case 절에도 해당하지 않을 때 실행된다. + +> 이 구문은 반드시 존재해야 하는 것은 아니며 필요할 때에만 선언할 수 있다. + +> default 절의 위치가 반드시 switch 문의 맨 마지막일 필요는 없다. + +- 예제 + +```c +int num = 2; +switch (num) +{ + case 1: + printf("입력하신 수는 1입니다.\n"); + break; + case 2: + printf("입력하신 수는 2입니다.\n"); + break; + case 3: + printf("입력하신 수는 3입니다.\n"); + break; + case 4: + printf("입력하신 수는 4입니다.\n"); + break; + case 5: + printf("입력하신 수는 5입니다.\n"); + break; + default: + printf("1부터 5까지의 수만 입력해 주세요!"); + break; +} +``` + +- 실행 결과 + +```c +입력하신 수는 2입니다. +``` + +> 각 case 절 및 default 절은 반드시 break 키워드를 포함하고 있어야 한다. +> break 키워드는 조건 값에 해당하는 case 절이나 default 절이 실행된 뒤에 +> 전체 switch 문을 빠져나가게 해준다. +만약에 break 키워드가 없다면, +조건에 해당하는 switch 문의 case 절 이후의 모든 case 절이 전부 실행될 것이다. + +> 다음 예제는 앞서 살펴본 예제에서 break 키워드를 모두 삭제한 예제이다. + +- 예제 + +```c +int num = 2; +switch (num) +{ + case 1: + printf("입력하신 수는 1입니다.\n"); + case 2: + printf("입력하신 수는 2입니다.\n"); + case 3: + printf("입력하신 수는 3입니다.\n"); + case 4: + printf("입력하신 수는 4입니다.\n"); + case 5: + printf("입력하신 수는 5입니다.\n"); + default: + printf("1부터 5까지의 수만 입력해 주세요!"); +} +``` + +- 실행 결과 + +```c +입력하신 수는 2입니다. +입력하신 수는 3입니다. +입력하신 수는 4입니다. +입력하신 수는 5입니다. +1부터 5까지의 수만 입력해 주세요! +``` + +> 위의 예제처럼 break 키워드가 없으면, 조건 값에 해당하는 case 절뿐만 아니라 +> 그 이후에 등장하는 모든 case 절과 default 절이 전부 실행됨을 알 수 있다. + +> 다음 예제는 조건 값으로 여러 개의 char형 문자를 검사하는 예제이다. +이렇게 switch 문의 조건으로 여러 개의 case 절을 사용하여 +여러 개의 조건을 한 번에 검사할 수 있다. + +- 예제 + +```c +char ch = 'a'; +switch (ch) +{ + case 'a': + case 'A': + printf("이 학생의 학점은 A입니다.\n"); + break; + case 'b': + case 'B': + printf("이 학생의 학점은 B입니다.\n"); + break; + case 'c': + case 'C': + printf("이 학생의 학점은 C입니다.\n"); + break; + case 'd': + case 'D': + printf("이 학생의 학점은 D입니다.\n"); + break; + case 'f': + case 'F': + printf("이 학생의 학점은 F입니다.\n"); + break; + default: + printf("학점을 정확히 입력해 주세요!(A, B, C, D, F)"); + break; +} +``` + +- 실행 결과 + +```c +이 학생의 학점은 A입니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-18_IterationStatement.md b/_posts/Language/C/2023-12-03-18_IterationStatement.md new file mode 100644 index 000000000000..4f95635f3d95 --- /dev/null +++ b/_posts/Language/C/2023-12-03-18_IterationStatement.md @@ -0,0 +1,188 @@ +--- +layout: single +title: Chapter 18 반복문 +date: 2023-12-03 12:21:17 +09:00 +categories: + - Language +tags: + - C +excerpt: 반복문에 관한 글입니다. +toc: true +--- + +# 1 반복문(iteration statements) + +- 반복문(iteration statements) + +> 반복문(iteration statements)이란 프로그램 내에서 +> 똑같은 명령을 일정 횟수만큼 반복하여 수행하도록 제어하는 명령문을 의미한다. + +> 프로그램이 처리하는 대부분의 코드는 반복적인 형태가 많으므로, 가장 많이 사용되는 제어문 중 하나이다. + +> C 언어에서 사용되는 대표적인 반복문의 형태는 다음과 같다. + +1. while 문 + +2. do / while 문 + +3. for 문 + +## 1.1 while 문 + +> while 문은 특정 조건을 만족할 때까지 계속해서 주어진 명령문을 반복 실행한다. + +> C 언어에서 while 문의 문법은 다음과 같다. + +- 문법 + +```c +while (조건식) +{ + 조건식의 결과가 참인 동안 반복적으로 실행하고자 하는 명령문; +} +``` + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/a65f40e0-df83-4ff0-9be6-c31c1041b430) + +> while 문은 우선 조건식이 참(true)인지를 판단하여, + 참이면 내부의 명령문을 실행한다. + 이렇게 내부의 명령문을 전부 실행하고 나면, + 다시 조건식으로 돌아와 또 한 번 참인지를 판단하게 된다. + +- 루프(loop) + +> 루프(loop)란 표현식의 검사를 통해 반복해서 실행되는 반복문을 의미한다. + +- 예제 + +```c +int i = 0; +int num = 5; + +while (i < num) +{ + printf("while 문이 %d 번째 반복 수행중입니다.\n", i + 1); + i++; // 이 부분을 삭제하면 무한 루프에 빠지게 됨 +} +printf("while 문이 종료된 후 변수 i의 값은 %d입니다.\n", i); +``` + +- 실행 결과 + +```c +while 문이 1 번째 반복 수행중입니다. +while 문이 2 번째 반복 수행중입니다. +while 문이 3 번째 반복 수행중입니다. +while 문이 4 번째 반복 수행중입니다. +while 문이 5 번째 반복 수행중입니다. +while 문이 종료된 후 변수 i의 값은 5입니다. +``` + +> while 문 내부에 조건식의 결과를 변경하는 명령문이 존재하지 않을 때는 +> 프로그램이 영원히 반복되게 된다. + 이것을 무한 루프(infinite loop)에 빠졌다고 한다. + 반복문에서 조건식의 거짓일때 반복문이 종료가되지만, + 무한루프는 조건식의 거짓이 없이 항상 참이므로 반복문이 종료되지 않고 + 무한히 실행되는 반복문을 말한다. + 무한 루프에 빠진 프로그램은 영원히 종료되지 않는다. + +> 무한 루프는 특별히 의도한 경우가 아니라면 반드시 피해야 하는 상황이다. + 따라서 while 문을 작성할 때는 조건식의 결과가 어느 순간 거짓(false)을 갖도록 + 조건식의 결과를 변경하는 명령문을 반드시 포함시켜야 한다. + +> 위의 예제에서 조건식의 결과를 변경하는 명령문인 i++를 제거하면, +> 변수 i의 값은 언제나 0이기 때문에 무한 루프에 빠지게 된다. + +> while 문에서 실행될 명령문이 한 줄 뿐이라면 중괄호({})를 생략할 수 있다. + +## 1.2 do / while 문 + +> while 문은 루프에 진입하기 전에 먼저 조건식부터 검사한다. +> 하지만 do / while 문은 먼저 루프를 한 번 실행한 후에 조건식을 검사한다. +> 즉, do / while 문은 조건식의 결과와 상관없이 무조건 한 번은 루프를 실행한다. + +> C 언어에서 do / while 문의 문법은 다음과 같다. + +- 문법 + +```c +do { +    조건식의 결과가 참인 동안 반복적으로 실행하고자 하는 명령문; +} while (조건식); +``` + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/45ed162d-a3ab-4dcf-bdd2-df22f10f76d1) + +- 예제 + +```c +int i = 0; +int num = 3;   + +do { +    printf("do / while 문이 %d 번째 반복 수행중입니다.\n", i + 1); +    i++; +} while (i > num); +printf("do / while 문이 종료된 후 변수 i의 값은 %d입니다.\n", i); +``` + +- 실행 결과 + +```c +do / while 문이 1 번째 반복 수행중입니다. +while 문이 종료된 후 변수 i의 값은 1입니다. +``` + +> 위의 예제가 만약 while 문이었다면 단 한 번의 출력도 없었을 것이다. +> 하지만 do / while 문은 조건식의 결과와 상관없이 무조건 한 번은 루프를 실행해준다. + +## 1.3 for 문 + +> for 문은 while 문과는 달리 자체적으로 +> 초기식, 조건식, 증감식을 모두 포함하고 있는 반복문이다. +> 따라서 while 문보다는 좀 더 간결하게 반복문을 표현할 수 있다. + +> C 언어에서 for 문의 문법은 다음과 같다. + +- 문법 + +```c +for (초기식; 조건식; 증감식)  +{ +    조건식의 결과가 참인 동안 반복적으로 실행하고자 하는 명령문; +} +``` + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/48b01857-ff32-449b-94eb-c4d7411c7d14) + +> 이때 for 문을 구성하는 초기식, 조건식, 증감식은 각각 생략될 수 있다. + +> for 문을 사용하면 앞선 예제의 while 문을 더욱 더 간결하게 표현할 수 있다. + +- 예제 + +```c +int i; +int num = 7;   + +for (i = 0; i < num; i++) +{ +    printf("for 문이 %d 번째 반복 수행중입니다.\n", i + 1); +} +printf("for 문이 종료된 후 변수 i의 값은 %d입니다.\n", i); +``` + +- 실행 결과 + +```c +for 문이 1 번째 반복 수행중입니다. +for 문이 2 번째 반복 수행중입니다. +for 문이 3 번째 반복 수행중입니다. +for 문이 4 번째 반복 수행중입니다. +for 문이 5 번째 반복 수행중입니다. +for 문이 6 번째 반복 수행중입니다. +for 문이 7 번째 반복 수행중입니다. +while 문이 종료된 후 변수 i의 값은 7입니다. +``` + +> for 문에서 실행될 명령문이 한 줄 뿐이라면 중괄호({})를 생략할 수 있다. diff --git a/_posts/Language/C/2023-12-03-19_ControlStatement.md b/_posts/Language/C/2023-12-03-19_ControlStatement.md new file mode 100644 index 000000000000..9dbda96dcce2 --- /dev/null +++ b/_posts/Language/C/2023-12-03-19_ControlStatement.md @@ -0,0 +1,147 @@ +--- +layout: single +title: Chapter 19 기타 제어문 +date: 2023-12-03 20:33:12 +09:00 +categories: Language +tags: C +excerpt: 기타 제어문에 관한 글입니다. +toc: true +--- + +# 1 루프의 제어 + +> 일반적으로 조건식의 검사를 통해 루프로 진입하면,  +> 다음 조건식을 검사하기 전까지 루프 안에 있는 모든 명령문을 실행한다. +> 하지만 continue 문과 break 문은 이러한 일반적인 루프의 흐름을 +> 사용자가 직접 제어할 수 있도록 해준다. + +## 1.1 continue 문 + +> continue 문은 루프 내에서 사용하여 해당 루프의 나머지 부분을 건너뛰고, + 바로 다음 조건식의 판단으로 넘어가게 한다. +> 보통 반복문 내에서 특정 조건에 대한 예외 처리를 하고자 할 때 자주 사용된다. + +> 다음 예제는 1부터 100까지의 정수 중에서 3의 배수를 제외하고 출력하는 예제이다. + +- 예제 + +```c +int i; +int except_num = 3;   + +for (i = 1; i <= 100; i++) +{ +    if (i % except_num == 0) +    { +        continue; +    } +    printf("%d ", i); +}   +``` + +- 실행 결과 + +```c +1 +2 +4 +5 +7 +... +97 +98 +100 +``` + +> 위의 예제에서 변수 i의 값이 3의 배수인 경우에는 continue 문을 이용하여 +> for 문의 printf() 함수 부분을 건너뛰고 있다. + +## 1.2 break 문 + +> break 문은 루프 내에서 사용하여 해당 반복문을 완전히 종료시킨 뒤, +> 반복문 바로 다음에 위치한 명령문을 실행한다. +> 즉 루프 내에서 조건식의 판단 결과에 상관없이 반복문을 완전히 빠져나가고 싶을 때 사용한다. + +> 다음 예제는 1부터 10까지의 합을 구하는 예제이다. + +- 예제 + +```c +int start_num = 1; +int end_num = 10; +int sum = 0;   + +while (1) +{ +    sum += start_num; +    if (start_num == end_num) +    { +        break; +    } +    start_num++; +} +``` + +- 실행 결과 + +```c +1부터 10까지 더한 값은 55입니다. +``` + +> 위의 예제에서는 변수 start_num의 값이 end_num의 값과 같아지면, +> 무조건 while 문을 종료하게 된다. + +> 다음 예제는 구구단에서 5단까지 각 단의 수만큼만 출력하는 예제이다. + +- 예제 + +```c +int i, j;   + +for (i = 2; i <= 5; i++) +{ +    for (j = 1; j <= 9; j++) +    { +        printf("%d * %d = %d\n", i, j, i * j); +        if (i == j) +        { +            printf("\n"); +            break; +        } +    } +}  +``` + +- 실행 결과 + +```c +2 * 1 = 2 +2 * 2 = 4 + +3 * 1 = 3 +3 * 2 = 6 +3 * 3 = 9 + +4 * 1 = 4 +4 * 2 = 8 +4 * 3 = 12 +4 * 4 = 16 + +5 * 1 = 5 +5 * 2 = 10 +5 * 3 = 15 +5 * 4 = 20 +5 * 5 = 25 +``` + +> 위의 예제는 두 개의 for 문을 중첩해서 사용하여 구구단을 출력하고 있다. + 이때 내부의 for 문은 변수 i와 j의 값이 같아지면, + break 문을 호출하여 내부의 for 문을 빠져나간다. + 따라서 구구단의 각 단이 해당 단의 수만큼만 출력될 수 있다. + +## 1.3 goto 문 + +> goto 문은 프로그램의 흐름을 지정된 레이블(label)로 무조건 변경시키는 명령문이다. + goto 문은 다른 제어문과는 달리 아무런 조건 없이 프로그램의 흐름을 옮겨준다. + 따라서 가장 손쉽게 사용할 수 있지만, 반면에 프로그램의 흐름을 매우 복잡하게 만들기도 한다. + 이러한 단점 때문에 현재는 디버깅 이외에는 거의 사용되지 않는다. diff --git a/_posts/Language/C/2023-12-03-20_CLanguageFunction.md b/_posts/Language/C/2023-12-03-20_CLanguageFunction.md new file mode 100644 index 000000000000..df8db1b54cf1 --- /dev/null +++ b/_posts/Language/C/2023-12-03-20_CLanguageFunction.md @@ -0,0 +1,197 @@ +--- +layout: single +title: Chapter 20 C 언어 함수 +date: 2023-12-03 20:48:01 +09:00 +categories: + - Language +tags: + - C +excerpt: C 언어 함수에 관한 글입니다. +toc: true +--- + +# 1 함수 + +- 함수 + +> 프로그래밍에서 함수(function)란 하나의 특별한 목적의 작업을 수행하기 위해  + 독립적으로 설계된 프로그램 코드의 집합을 의미한다. + + >C 프로그램은 이러한 함수들로 구성되며, + 포함된 함수들을 사용하여 프로그램의 목적을 달성하게 된다. + +> C 언어에서 함수는 크게 표준 함수와 사용자 정의 함수로 구분할 수 있다. + +## 1.1 함수를 사용하는 이유 + +> 함수를 사용하는 가장 큰 이유는 바로 반복적인 프로그래밍을 피할 수 있기 때문이다. +> 프로그램에서 특정 작업을 여러 번 반복해야 할 때는 해당 작업을 수행하는 함수를 작성하면 된다. +> 그리고서 프로그램이 필요할 때마다 작성한 함수를 호출하면 해당 작업을 반복해서 수행할 수 있다. + +> 또한, 프로그램을 여러 개의 함수로 나누어 작성하면, 모듈화로 인해 전체적인 코드의 가독성이 좋아진다. +> 그리고 프로그램에 문제가 발생하거나 기능의 변경이 필요할 때에도 손쉽게 유지보수를 할 수 있다. +> 함수의 크기에 대해서 정확히 명시된 규칙은 없으나, +> 대략 하나의 기능을 하나의 함수로 만드는 것이 가장 좋다. + +## 1.2 함수의 정의 + +> C 언어에서 사용자 정의 함수를 정의하는 방법은 다음 그림과 같다. + +![함수 선언](https://tcpschool.com/lectures/img_c_function_structure.png) + +1. 반환 타입(return type) : 함수가 모든 작업을 마치고 반환하는 데이터의 타입을 명시한다. + +2. 함수 이름 : 함수를 호출하기 위한 이름을 명시한다. + +3. 매개변수 목록(parameters) : 함수 호출 시에 전달되는 인수의 값을 저장할 변수들을 명시한다. + +4. 함수 몸체 : 함수의 고유 기능을 수행하는 명령문의 집합이다. + +> 함수 호출 시에는 여러 개의 인수를 전달할 수 있지만, +> 함수가 반환할 수 있는 값은 1개를 넘지 못한다. +> 또한, 함수의 특성에 따라 인수나 반환값이 하나도 없는 함수도 존재할 수 있다. + +>다음 예제에서는 인수로 전달받은 두 수 중에서 더 큰 수를 반환하는 bigNum() 함수를 정의하여 사용한다. + +- 예제 + +```c +#include + +int bigNum(int num01, int num02) // 함수의 정의 +{ +    if (num01 >= num02) +    { +        return num01; +    } +    else +    { +        return num02; +    } +} + +int main(void) +{ +    int result;   + +    result = bigNum(3, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(3, 1); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(7, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    return 0; +}   +``` + +- 실행 결과 + +```c +두 수 중 더 큰수는 5입니다. +두 수 중 더 큰수는 3입니다. +두 수 중 더 큰수는 7입니다. +``` + +## 1.3 함수의 원형 선언 + +> C언어에서 함수를 정의할 때는 그 위치가 매우 중요하다. + +> 다음 예제는 함수 정의의 위치만을 바꾼 예제이다. + +- 예제 + +```c +#include + +int main(void) +{ +    int result;   + +    result = bigNum(3, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(3, 1); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(7, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    return 0; +}   + +int bigNum(int num01, int num02) // 함수의 정의 +{ +    if (num01 >= num02) +    { +        return num01; +    } +    else +    { +        return num02; +    } +} +``` + +> C 언어에서는 가장 먼저 main() 함수가 컴파일러에 의해 컴파일된다. + +> 위의 예제에서 컴파일러는 main() 함수에 등장하는 bigNum() 함수를 +> 아직 알지 못하기 때문에 컴파일 오류를 발생시킨다. +> 따라서 컴파일러에 bigNum() 함수는 나중에 정의되어 있다고 알려줘야 한다. +> 그 역할을 하는 것이 바로 함수의 원형(prototype) 선언이다. + +> 위와 같이 차례대로 한 번에 컴파일하는 방식을 단일 패스(one pass) 컴파일 방식이라고 한다. +> 하지만 하드웨어의 발달로 컴파일러에 따라 여러 번에 걸쳐 컴파일하는 +> 다중 패스(multi-pass) 방식이 많아지고 있다. + +> 다중 패스 방식의 컴파일러에서는 함수의 원형을 선언하지 않아도 +> 컴파일 오류를 발생시키지 않는다. +> 하지만 오래된 컴파일러는 대부분 단일 패스 방식으로 컴파일하므로, +> C 표준에서는 여전히 함수의 원형을 정의하고 있다. + +> 함수의 원형 선언은 다음과 같은 방식으로 선언된다. + +- 문법 + +```c +반환타입 함수이름(매개변수타입); +``` + +> 다음 예제는 함수의 원형 선언을 추가한 예제이다. +> 이렇게 함수의 원형은 main() 함수 앞에 미리 선언되어야 한다. + +- 예제 + +```c +#include +int bigNum (int, int); // 함수의 원형 선언   + +int main(void) +{ +    int result;   + +    result = bigNum(3, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(3, 1); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    result = bigNum(7, 5); // 함수의 호출 +    printf("두 수 중 더 큰수는 %d입니다.\n", result); +    return 0; +}   + +int bigNum(int num01, int num02) // 함수의 정의 +{ +    if (num01 >= num02) +    { +        return num01; +    } +    else +    { +        return num02; +    } +} +``` + +- 실행 결과 + +```c +두 수 중 더 큰수는 5입니다. +두 수 중 더 큰수는 3입니다. +두 수 중 더 큰수는 7입니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-03-21_ValidRangeOfVariable.md b/_posts/Language/C/2023-12-03-21_ValidRangeOfVariable.md new file mode 100644 index 000000000000..6163664e48bd --- /dev/null +++ b/_posts/Language/C/2023-12-03-21_ValidRangeOfVariable.md @@ -0,0 +1,253 @@ +--- +layout: single +title: Chapter 21 변수의 유효 범위 +date: 2023-12-03 21:03:20 +09:00 +categories: + - Language +tags: + - C +excerpt: 변수의 유효 범위에 관한 글입니다. +toc: true +--- + +# 1 변수의 유효 범위(variable scope) + +> C 언어에서는 변수의 선언 위치에 따라 해당 변수의 유효 범위, +> 메모리 반환 시기, 초기화 여부, 저장되는 장소 등이 변경된다. + +> C 언어에서 변수는 위와 같은 특징들을 기준으로 다음과 같이 나눌 수 있다. + +1. 지역 변수(local variable) + +2. 전역 변수(global variable) + +3. 정적 변수(static variable) + +4. 레지스터 변수(register variable) + + +## 1,1 메모리의 구조 + +> 컴퓨터의 운영체제는 프로그램의 실행을 위해 다양한 메모리 공간을 제공한다. + C 프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 다음과 같다. + +1. 코드(code) 영역 + +2. 데이터(data) 영역 + +3. 스택(stack) 영역 + +4. 힙(heap) 영역 + + +## 1.2 지역 변수(local variable) + +- 지역 변수(local variable) + +> 지역 변수(local variable)란 '블록' 내에서 선언된 변수를 의미한다. + 지역 변수는 변수가 선언된 블록 내에서만 유효하며, 블록이 종료되면 메모리에서 사라진다. + +> 이러한 지역 변수는 메모리상의 스택(stack) 영역에 저장되며, +> 초기화하지 않으면 의미 없는 값(쓰레기값)으로 초기화된다. +함수의 매개변수 또한 함수 내에서 정의되는 지역 변수로 취급된다. + +- 예제 + +```c +#include    +void local(void);   + +int main(void) +{ +    int i = 5; +    int var = 10; +    printf("main() 함수 내의 지역 변수 var의 값은 %d입니다.\n", var);   + +    if (i < 10) +    { +        local(); +        int var = 30; +        printf("if 문 내의 지역 변수 var의 값은 %d입니다.\n", var); +    }   + +    printf("현재 지역 변수 var의 값은 %d입니다.\n", var); +    return 0; +}   + +void local(void) +{ +    int var = 20; +    printf("local() 함수 내의 지역 변수 var의 값은 %d입니다.\n", var); +}   +``` + +- 실행 결과 + +```c +main() 함수 내의 지역 변수 var의 값은 10입니다. +local() 함수 내의 지역 변수 var의 값은 20입니다. +if 문 내의 지역 변수 var의 값은 30입니다. +현재 지역 변수 var의 값은 10입니다. +``` + +> 위의 예제에서 변수 var은 한 번은 main() 함수 내에서, +> 또 한 번은 if 문에서, 마지막은 local() 함수 내에서 선언된다. +이처럼 같은 이름의 변수 var은 모두 다른 중괄호({}) 영역에서 선언되었으며, +이러한 중괄호 영역을 블록(block)이라고 한다. +이렇게 변수의 유효 범위는 변수가 선언된 블록을 기준으로 설정되며, +해당 블록이 끝나면 모든 지역 변수는 메모리에서 사라지게 된다. + +>위의 변수의 이름으로 같은 이름을 여러 번 사용하는 것은 +> 구문 상 에러를 발생시키지는 않지만,  +>바람직하지 못한 방식이다. + +> 한 블록 내에서 같은 이름의 변수를 또다시 선언하려고 하면 컴파일러는 오류를 발생시킨다. + +## 1.3 전역 변수(global variable) + +- 전역 변수(global variable) + +>전역 변수(global variable)란 함수의 외부에서 선언된 변수를 의미한다. + +> 전역 변수는 프로그램의 어디에서나 접근할 수 있으며, +> 프로그램이 종료되어야만 메모리에서 사라진다. + +> 이러한 전역 변수는 메모리상의 데이터(data) 영역에 저장되며, +> 직접 초기화하지 않아도 0으로 자동 초기화된다. + +- 예제 + +```c +#include    +void local(void); +int var; // 전역 변수 선언     + +int main(void) +{ +    printf("전역 변수 var의 초깃값은 %d입니다.\n", var);   +    int i = 5; +    int var = 10; // 지역 변수 선언 +    printf("main() 함수 내의 지역 변수 var의 값은 %d입니다.\n", var);   + +    if (i < 10) +    { +        local(); +        printf("현재 변수 var의 값은 %d입니다.\n", var); // 지역 변수에 접근 +    }   + +    printf("더 이상 main() 함수에서는 전역 변수 var에 접근할 수가 없습니다.\n"); +    return 0; +}   + +void local(void) +{ +    var = 20; // 전역 변수의 값 변경 +    printf("local() 함수 내에서 접근한 전역 변수 var의 값은 %d입니다.\n", var); +}   +``` + +- 실행 결과 + +```c +전역 변수 var의 초기값은 0입니다. +main() 함수 내의 지역 변수 var의 값은 10입니다. +local() 함수 내에서 접근한 전역 변수 var의 값은 20입니다. +현재 변수 var의 값은 10입니다. +더 이상 main() 함수에서는 전역 변수 var에 접근할 수가 없습니다. +``` + +> 위의 예제에서 전역 변수 var와 같은 이름의 지역 변수 var가 main() 함수 내부에서 선언된다. +이 지역 변수가 선언되기 전까지는 main() 함수에서도 전역 변수 var에 접근할 수 있다. +하지만 지역 변수 var가 선언된 후에는 +main() 함수에서 전역 변수 var로 접근할 방법이 없어진다. +왜냐하면, 블록 내에서 선언된 지역 변수는 같은 이름의 전역 변수를 덮어쓰기 때문이다. + +>따라서 이처럼 전역 변수와 같은 이름으로 지역 변수를 선언하는 것은 좋지 않다. + +> 또한, 여러 개의 파일로 구성된 프로그램에서 외부 파일의 전역 변수를 사용하기 위해서는 +> extern 키워드를 사용해 다시 선언해야 줘야한다. + +## 1.4 정적 변수(static variable) + +- 정적 변수(static variable) + +>C 언어에서 정적 변수(static variable)란 static 키워드로 선언한 변수를 의미한다. + +>이렇게 선언된 정적 변수는 지역 변수와 전역 변수의 특징을 모두 가지게 된다. +함수 내에서 선언된 정적 변수는 전역 변수처럼 단 한 번만 초기화되며 +(초기화는 최초 실행 시 단 한번만 수행됨), 프로그램이 종료되어야 메모리상에서 사라진다. +또한, 이렇게 선언된 정적 변수는 지역 변수처럼 해당 함수 내에서만 접근할 수 있다. + +- 예제 + +```c +#include    +void local(void); +void staticVar(void);   + +int main(void) +{ +    int i;   +    for (i = 0; i < 3; i++) +    { +        local(); +        staticVar(); +    }   +    return 0; +}   + +void local(void) +{ +    int count = 1; +    printf("local() 함수가 %d 번째 호출되었습니다.\n", count); +    count++; +}   + +void staticVar(void) +{ + ① static int static_count = 1; +    printf("staticVar() 함수가 %d 번째 호출되었습니다.\n", static_count); +    static_count++; +} +``` + +- 실행 결과 + +```c +local() 함수가 1 번째 호출되었습니다. +staticVar() 함수가 1 번째 호출되었습니다. +local() 함수가 1 번째 호출되었습니다. +staticVar() 함수가 2 번째 호출되었습니다. +local() 함수가 1 번째 호출되었습니다. +staticVar() 함수가 3 번째 호출되었습니다. +``` + +>위의 예제는 지역 변수로 선언된 count와  +>정적 변수로 선언된 static_count를 서로 비교하는 예제이다. +지역 변수인 count는 함수의 호출이 끝날 때마다 메모리상에서 사라진다. +하지만 정적 변수인 static_count는 함수의 호출이 끝나도 메모리상에서 사라지지 않고, +다음 함수 호출 때 이전의 데이터를 그대로 가지고 있다. + +>정적 변수 static_count의 초기화를 수행하는 ①번 라인의 코드는 최초로 실행될 때 +>단 한 번만 수행되며, 두 번째부터는 수행되지 않는다. +또한, static_count는 전역 변수와는 달리 자신이 선언된 staticVar() 함수 +이외의 영역에서는 호출할 수 없다. + +## 1.5 레지스터 변수(register variable) + +- 레지스터 변수 + +> 레지스터 변수란 지역 변수를 선언할 때 register 키워드를 붙여 선언한 변수를 의미한다. + +>이렇게 선언된 레지스터 변수는 CPU의 레지스터(register) 메모리에 저장되어 빠르게 접근할 수 있게 된다. + +> 하지만 컴퓨터의 레지스터는 매우 작은 크기의 메모리이므로, +> 이 영역에 변수를 선언하기 힘든 경우도 많다. +그럴 때 C 컴파일러는 해당 변수를 그냥 지역변수로 선언하게 된다. + +- 변수의 종류 + +![스크린샷(753) - 복사본](https://github.com/EunChong999/EunChong999/assets/136239807/2ea267f4-2562-41d8-940e-a0c99367c6f9) + +![스크린샷(753)](https://github.com/EunChong999/EunChong999/assets/136239807/7a0f722f-0ff2-4957-9cf8-b8d878996ed8) + diff --git a/_posts/Language/C/2023-12-04-22_RecursiveCall.md b/_posts/Language/C/2023-12-04-22_RecursiveCall.md new file mode 100644 index 000000000000..f2a4fabeb1d6 --- /dev/null +++ b/_posts/Language/C/2023-12-04-22_RecursiveCall.md @@ -0,0 +1,123 @@ +--- +layout: single +title: Chapter 22 재귀 호출 +date: 2023-12-04 18:49:03 +09:00 +categories: + - Language +tags: + - C +excerpt: 재귀 호출에 관한 글입니다. +toc: true +--- + +# 1 재귀 호출(recursive call) + +- 함수 + +>함수란 하나의 작업을 수행하기 위해 독립적으로 설계된 프로그램 코드의 집합을 의미한다. + +>C 프로그램은 이러한 함수들로 구성되며, +>포함된 함수들을 사용하여 프로그램의 목적을 달성하게 된다. + +- 재귀 호출(recursive call) + +>재귀 호출(recursive call)이란 함수 내부에서 함수가 자기 자신을 또다시 호출하는 행위를 의미한다. + +>이러한 재귀 호출은 자기가 자신을 계속해서 호출하므로, 끝없이 반복되게 된다. +따라서 함수 내에 재귀 호출을 중단하도록 조건이 변경될 명령문을 반드시 포함해야 한다. + +> 재귀 호출은 알고리즘이나 자료 구조론에서는 매우 중요한 개념 중 하나이다. +또한, 재귀 호출을 사용하면 복잡한 문제도 매우 간단하게 논리적으로 접근하여 표현할 수 있다. + +## 1.1 재귀 호출의 개념 + +>다음은 재귀 호출을 사용하지 않고 1부터 n까지의 합을 구하는 함수에 대한 예제이다. + +- 예제 + +```c +int sum(int n) { +    int i; +    int result = 0; + +    for (i = 1; i <= n; i++) +    { +        result += i; +    } + +    return result; +}   +``` + +>위의 예제에서 sum() 함수는 재귀 호출을 사용하지 않고 만든 함수이다. +이러한 함수는 그냥 봐서는 그 목적을 바로 알 수 없으며, +코드를 해석해야 무슨 목적으로 만든 함수인지 알 수 있다. +즉 변수 i와 result는 왜 정의됐으며, for 문은 왜 사용되었는지 바로 알 수가 없다. + +> 재귀 호출을 사용하여 1부터 n까지의 합을 구하는 rSum() 함수를 만들 수 있다. +1부터 4까지의 합을 구하는 알고리즘은 다음과 같습니다. + +1. 1부터 4까지의 합은 1부터 3까지의 합에 4를 더하면 된다. + +2. 1부터 3까지의 합은 1부터 2까지의 합에 3을 더하면 된다. + +3. 1부터 2까지의 합은 1부터 1까지의 합에 2를 더하면 된다. + +4. 1부터 1까지의 합은 그냥 1이다. + +>위와 같이 논리적인 재귀 알고리즘을 구상하고 나면, +>그것을 토대로 의사 코드를 작성할 수 있다. +위의 알고리즘을 의사 코드(pseudo code)로 작성하면 다음과 같다. + +- 의사 코드 + +```c +시작 +    1. n이 1이 아니면, 1부터 (n-1)까지의 합에 n을 더한 값을 반환함. +    2. n이 1이면, 그냥 1을 반환함. +끝 +``` + +- 의사 코드(pseudo code) + +>의사 코드(pseudo code)란 특정 프로그래밍 언어의 문법에 맞춰 작성된 것이 아닌,  +>일반적인 언어로 알고리즘을 표현한 코드를 의미한다. + +>이렇게 작성된 의사 코드는 재귀 호출을 이용해 다음 예제와 같이 바로 구현할 수 있게 된다. + +- 예제 + +```c +int rSum(int n) +{ +    if (n == 1)           // n이 1이면, 그냥 1을 반환함. +    { +          return 1; +    } +    return n + rSum(n-1); // n이 1이 아니면, n을 1부터 (n-1)까지의 합과 더한 값을 반환함. +} +``` + +- 실행 결과 + +```c +1부터 5까지의 합은 15입니다. +``` + +> 위의 예제에서 if 문이 존재하지 않으면, +> 이 프로그램은 실행 직후 스택 오버플로우(stack overflow)에 의해 종료될 것이다. +따라서 if 문처럼 재귀 호출을 중단하기 위한 조건문을 반드시 포함해야 한다. + +- 스택 오버플로우 + +>스택 오버플로우(stack overflow)란 메모리 구조 중 스택(stack) 영역에서 +>해당 프로그램이 사용할 수 있는 메모리 공간 이상을 +>사용하려고 할 때 발생하는 상황을 의미한다. + +>이처럼 재귀 호출은 다양한 알고리즘을 표현한 의사 코드를 그대로 코드로 옮길 수 있게 해준다. +따라서 재귀 호출은 직관적인 프로그래밍을 하는 데 많은 도움을 준다. + +>하지만 이러한 재귀 호출은 비재귀 호출보다 실행 시간이 오래 걸리는 단점을 가지고 있다. + +>재귀호출의 장점 : 코드의 간결함 +재귀호출의 단점 : 무한 재귀호출의 위험성, 성능 상의 문제 \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-23_1DArrangement.md b/_posts/Language/C/2023-12-04-23_1DArrangement.md new file mode 100644 index 000000000000..11723ce9d2f0 --- /dev/null +++ b/_posts/Language/C/2023-12-04-23_1DArrangement.md @@ -0,0 +1,241 @@ +--- +layout: single +title: Chapter 23 1차원 배열 +date: 2023-12-04 18:49:47 +09:00 +categories: + - Language +tags: + - C +excerpt: 1차원 배열에 관한 글입니다. +toc: true +--- + +# 1 배열(array) + +- 배열(array) + +>배열(array)이란 같은 타입의 변수들로 이루어진 유한 집합을 의미한다. + +- 배열 요소(element) + +> 배열 요소(element)란 배열을 구성하는 각각의 값을 의미한다. + +- 인덱스(index) + +>인덱스(index)란 배열에서의 위치를 가리키는 숫자를 의미한다. + +>C 언어에서 인덱스는 언제나 0부터 시작하며, 0을 포함한 양의 정수만을 가질 수 있다. + +> 배열은 같은 종류의 데이터를 많이 다뤄야 하는 경우에 +> 사용할 수 있는 가장 기본적인 자료 구조이다. + +>배열은 선언되는 형식에 따라 1차원 배열, 2차원 배열뿐만 아니라 +>그 이상의 다차원 배열로도 선언할 수 있다. +하지만 현실적으로 이해하기가 쉬운 2차원 배열까지가 많이 사용된다. + + + +## 1.1 1차원 배열 + +>1차원 배열은 가장 기본적인 배열로 다음과 같은 문법에 따라 선언된다. + +- 문법 + +```c +타입 배열이름[배열길이]; +``` + +> 타입은 배열 요소로 들어가는 변수의 타입을 명시한다. +배열 이름은 배열이 선언된 후에 배열로 접근하기 위해 사용된다. +배열의 길이는 해당 배열이 몇 개의 배열 요소를 가지게 되는지 명시한다. + +>C 언어에서는 배열을 선언만 하고 초기화하지 않으면, +>각 배열 요소에 아무런 의미를 가지지 않는 쓰레기값이 저장되어 있게 된다. +따라서 초기화되지 않은 배열은 사용하지 않도록 주의를 기울여야 한다. + +- 예제 + +```c +int i; +int sum = 0; +int grade[3];        // 길이가 3인 int형 배열 선언   + +/* 배열의 초기화 */ +grade[0] = 85;       // 국어 점수 +grade[1] = 65;       // 영어 점수 +grade[2] = 90;       // 수학 점수   + +for (i = 0; i < 3; i++) +{ +    sum += grade[i]; // 인덱스를 이용한 배열의 접근 +}   +printf("국영수 과목 총 점수 합계는 %d점이고, 평균 점수는 %f점입니다.\n", sum, (double)sum/3);   +``` + +- 실행 결과 + +```c +국영수 과목 총 점수 합계는 240점이고, 평균 점수는 80.000000점입니다. +``` + +>위의 예제는 길이가 3인 int형 배열을 선언하고 있다. +또한, 0부터 시작하는 인덱스(index)를 이용하면 각각의 배열 요소에 따로 접근할 수 있다. + +>다음 그림은 위의 예제에서 사용된 배열 grade가 메모리 상에서 어떻게 저장되는지를 보여준다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/a7a858ca-4a3f-4c4b-a559-3586026b8107) + + +>위의 그림처럼 언제나 배열의 이름은 배열의 첫 번째 요소와 같은 주소를 가리키고 있다. + + + +## 1.2 배열의 선언과 동시에 초기화 하는 방법 + +>C 언어에서는 변수와 마찬가지로 배열도 선언과 동시에 초기화할 수 있다. + +>다음과 같이 중괄호({})를 사용하여 초깃값을 나열한 것을 초기화 리스트라고 한다. + +- 문법 + +```c +타입 배열이름[배열길이] = {배열요소1, 배열요소2, ...}; +``` + +>단, 초기화 리스트의 타입과 배열의 타입은 반드시 일치해야 한다. +만약에 초기화 리스트의 개수가 배열의 총 길이보다 적으면, +배열의 앞에서부터 차례대로 초기화된다. +이때 초기화되지 못한 나머지 배열 요소는 모두 0으로 자동 초기화된다. + +>다음 예제는 배열을 선언과 동시에 초기화하는 예제이다. + +- 예제 + +```c +int i; +int sum = 0; +int grade[3] = {85, 65, 90}; // 길이가 3인 int형 배열의 선언과 동시에 초기화   + +for (i = 0; i < 3; i++) +{ +    sum += grade[i]; +}   +printf("국영수 과목 총 점수 합계는 %d이고, 평균 점수는 %f입니다.\n", sum, (double)(sum/3));   +``` + +- 실행 결과 + +```c +국영수 과목 총 점수 합계는 240이고, 평균 점수는 80.000000입니다. +``` + + + +## 1.3 배열의 길이 자동 설정 + +>C 언어에서는 초기화 리스트에 맞춰 자동으로 배열의 길이를 설정할 수도 있다. + +>다음과 같이 배열의 길이를 따로 입력하지 않은 배열은 +>초기화 리스트의 배열 요소의 개수에 맞춰 자동으로 배열의 길이가 설정된다. + +- 문법 + +```c +타입 배열이름[] = {배열요소1, 배열요소2, ...}; +``` + +>다음 예제에서 int형 배열 arr의 길이는 자동으로 3으로 설정됨과 동시에 +>초기화 리스트에 의해 초기화된다. + +- 예제 + +```c +int arr[] = {1, 2, 3}; +``` + + + +## 1.4 배열의 특징 + +>C 언어에서 배열은 다음과 같은 특징을 가진다. + +1. 배열의 길이를 선언할 때에는 반드시 상수를 사용해야 한다. + +2. 배열 요소의 인덱스는 언제나 0부터 시작한다. + +3. C 컴파일러는 배열의 길이를 전혀 신경 쓰지 않는다. + +- 예제 + +```c +int i; +int sum = 0; +int grade[3] = {85, 65, 90}; // grade[0], grade[1], grade[2]만 선언 및 초기화 +grade[3] = 100;              // grade[3]를 선언하지 않고 초기화 진행   + +for (i = 0; i < 4; i++)      // grade[3]도 수식에 포함 +{ +    sum += grade[i]; +}   +printf("국영수 과목 총 점수 합계는 %d이고, 평균 점수는 %f입니다.\n", sum, (double)sum/3);   +``` + +- 실행 결과 + +```c +국영수 과목 총 점수 합계는 340이고, 평균 점수는 113.333333입니다. +``` + +> 위의 예제에서는 크기가 3인 int형 배열 grade를 선언하고 있다. +즉, 배열 grade의 배열 요소는 grade[0], grade[1], grade[2]만이 존재한다. +하지만 존재하지도 않는 grade[3]이라는 배열 요소의 초기화를 진행하고, +반복문을 통해 수식에서도 이용한다. + +>이때 C 컴파일러는 오류는 커녕 수식에서까지 이 배열 요소를 이용하여 결과를 출력한다. +하지만 이 결과는 개발자가 전혀 의도하지 않은 결과물이며, +이러한 프로그램은 종종 예상치 못한 결과를 내주기도 한다. + +>위와 같이 C 언어에서는 컴파일러가 +>일일이 배열의 길이 등을 검사하여 오류를 출력해 주지 않는다. +따라서 C 언어로 프로그래밍할 때에는 이런 계산을 언제나 개발자가 직접 신경 써야 한다. + + + +## 1.5 배열이 차지하는 메모리의 크기 + +>C 언어에서 배열을 복사하거나 배열 요소에 특정 작업을 하고 싶을 때는  +>해당 배열이 차지하는 메모리의 크기를 정확히 알고 있어야만 한다. + +>배열이 차지하는 총 메모리의 크기는 다음 수식을 사용하여 구할 수 있다. + +- 수식 + +```c +배열이 차지하는 메모리의 크기 = 배열의 길이 X sizeof(타입) +``` + +>배열의 길이를 알고 싶을 때에는 다음 수식을 사용하여 구할 수 있다. + +- 수식 + +```c +배열의 길이 = sizeof(배열 이름) / sizeof(배열 이름[0]) +``` + +>위의 수식에서 배열 이름[0]은 해당 배열의 타입을 표현하기 위해서 사용되었다. + +>다음 예제는 수식을 이용하여 배열의 길이는 구하는 예제이다. + +- 예제 + +```c +int grade[] = {85, 65, 90};                     // 배열의 길이를 명시하지 않음 +int arr_len = sizeof(grade) / sizeof(grade[0]); // 배열의 길이를 구하는 공식   +printf("배열 arrGrade의 길이는 %d입니다.\n", arr_len); +``` + +- 실행 결과 + +```c +배열 grade의 길이는 3입니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-24_MultidimensionalArrangement.md b/_posts/Language/C/2023-12-04-24_MultidimensionalArrangement.md new file mode 100644 index 000000000000..5f07f127db0a --- /dev/null +++ b/_posts/Language/C/2023-12-04-24_MultidimensionalArrangement.md @@ -0,0 +1,220 @@ +--- +layout: single +title: Chapter 24 다차원 배열 +date: 2023-12-04 18:50:48 +09:00 +categories: + - Language +tags: + - C +excerpt: 다차원 배열에 관한 글입니다. +toc: true +--- + +# 1 다차원 배열(multi-dimensional array) + +- 다차원 배열(multi-dimensional array) + +> 다차원 배열(multi-dimensional array)이란 2차원 이상의 배열을 의미하며, +> 배열 요소로 또 다른 배열을 가지는 배열을 의미한다. + +>즉, 2차원 배열은 배열 요소로 1차원 배열을 가지는 배열이며, +3차원 배열은 배열 요소로 2차원 배열을 가지는 배열이고, +4차원 배열은 배열 요소로 3차원 배열을 가지는 배열인 것이다. + +## 1.1 2차원 배열(two dimensional array) + +- 2차원 배열(two dimensional array) + +>2차원 배열(two dimensional array)이란 배열의 요소로 1차원 배열을 가지는 배열을 의미한다. + +>C 언어에서는 2차원 배열을 나타내는 타입을 따로 제공하지 않는다. +대신에 1차원 배열의 배열 요소로 또 다른 1차원 배열을 사용하여 2차원 배열을 나타낼 수 있다. + +>2차원 배열은 다음과 같은 문법에 따라 선언할 수 있다. + +- 문법 + +```c +타입 배열이름[행의길이][열의길이]; +``` + +>타입은 배열 요소로 저장되는 변수의 타입을 설정한다. +배열 이름은 배열이 선언된 후에 배열에 접근하기 위해 사용된다. + +>다음 그림은 2차원 배열을 이해하기 쉽도록 도식적으로 표현한 그림이다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/8db566b8-de3f-4f23-913f-24e55a7d3d1f) + +>하지만 컴퓨터의 메모리는 위와 같은 입체적 공간이 아닌 +>선형 공간이므로 실제로는 다음 그림과 같이 저장된다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/40176c6f-19e3-4d91-b672-5fdf727017d7) + +>다음 예제는 앞선 그림을 C 프로그램으로 작성한 예제이다. + +- 예제 + +```c +int arr01[6] = {10, 20, 30, 40, 50, 60}; +int arr02[2][3] = {10, 20, 30, 40, 50, 60};   +``` + +- 실행 결과 + +```c +arr01의 배열 요소의 값 +10 20 30 40 50 60 +arr02의 배열 요소의 값 +10 20 30 40 50 60 +``` + + + +## 1.2 배열의 선언과 동시에 초기화하는 방법 + +>1차원 배열과 마찬가지로 2차원 배열도 선언과 동시에 초기화할 수 있다. +2차원 배열은 1차원 배열과는 달리 여러 방식으로 초기화할 수 있다. + +1. 1차원 배열의 초기화 형태를 따르는 방식 + +2. 배열의 모든 요소를 초기화하는 방식 + +3. 배열의 일부 요소만을 초기화하는 방식 + + + +### 1.2.1 1차원 배열의 초기화 형태를 따르는 방식 + +> C 언어에서는 2차원 배열을 1차원 배열의 초기화 형태로도 초기화할 수 있다. + +- 문법 + +```c +타입 배열이름[행의길이][열의길이] = {배열요소[0][0], 배열요소[0][1], ..., 배열요소[1][0], 배열요소[1][1], ..., 배열요소[2][0], 배열요소[2][1], ...}; +``` + +>이 방식으로는 2차원 배열의 배열 요소 [0][0]부터 차례대로 초기화된다. +만약에 초기화하는 배열 요소의 개수가 배열의 총 길이보다 적으면, +나머지 배열 요소는 모두 0으로 초기화된다. + + + +### 1.2.2 배열의 모든 요소를 초기화하는 방식 + +>C 언어에서는 2차원 배열의 모든 요소를 초기화할 수 있다. + +- 문법 + +```c +타입 배열이름[행의길이][열의길이] = +{ +    {배열요소[0][0], 배열요소[0][1], ...}, +    {배열요소[1][0], 배열요소[1][1], ...}, +    {배열요소[2][0], 배열요소[2][1], ...}, +    ... +}; +``` + +>이 방식은 1차원 배열의 초기화 형태를 따르는 방식과 결과는 똑같다. + 하지만 좀 더 직관적으로 2차원 배열의 모습을 알 수 있으므로  + 보통 이 방식을 가장 많이 사용한다. + +>다음 예제는 두 가지 방식을 각각 사용하여 배열을 선언하고 초기화하는 예제이다. + +- 예제 + +```c +int arr01[2][3] = {10, 20, 30, 40, 50, 60}; +int arr02[2][3] = { +    {10, 20, 30}, +    {40, 50, 60} +};   +``` + +- 실행 결과 + +```c +arr01의 배열 요소의 값 +10 20 30 40 50 60 +arr02의 배열 요소의 값 +10 20 30 40 50 60 +``` + + + +### 1.2.3 배열의 일부 요소만을 초기화하는 방식 + +>C 언어에서는 2차원 배열의 일부 요소만을 초기화할 수도 있다. + +>이 방식으로는 다음 예제와 같이 2차원 배열의 원하는 배열 요소만을 초기화할 수 있다. +이때 초기화하지 않은 배열 요소는 모두 0으로 자동초기화된다. + +- 예제 + +```c +int arr[3][4] = { +    {10, 20}, +    {30, 40, 50, 60}, +    {0, 0, 70, 80} +}; +``` + +- 실행 결과 + +```c +  10  20   0   0 +  30  40  50  60 +   0   0  70  80 +``` + +>위의 예제에서 2차원 배열 열의 길이를 구할 때 사용하는 수식은 다음과 같다. + +- 수식 + +```c +arr_col_len = sizeof(arr[0]) / sizeof(arr[0][0]); // 2차원 배열의 열의 길이를 계산함 +``` + +>열의 길이는 sizeof(arr[0])으로 먼저 2차원 배열 한 행의 길이를 구한 후에, +>그 값을 배열 타입의 크기로 나누어서 구합니다. + +>열의 길이를 이용하면 2차원 배열 행의 길이도 구할 수 있다. + +- 수식 + +```c +arr_row_len = (sizeof(arr) / arr_col_len) / sizeof(arr[0][0]); // 2차원 배열의 행의 길이를 계산함 +``` + +>행의 길이는 sizeof(arr) / arr_col_len으로 먼저 2차원 배열 한 열의 길이를 구한 후에, +>그 값을 배열 타입의 크기로 나누어서 구한다. + + + +### 1.2.4 배열의 길이 자동 설정 + +>1차원 배열과 마찬가지로 2차원 배열도 배열의 길이를 명시하지 않고, +>자동으로 배열의 길이를 설정할 수 있다. +단, 행의 길이는 생략할 수 있지만, 열의 길이는 반드시 명시해야 한다. + +>다음 예제는 앞선 예제에서 행의 길이를 생략한 예제로, 같은 결과를 출력한다. + +- 예제 + +```c +int arr[][4] = { +    {10, 20}, +    {30, 40, 50, 60}, +    {0, 0, 70, 80} +}; +``` + +- 실행 결과 + +```c +  10  20   0   0 +  30  40  50  60 +   0   0  70  80 +``` + +>위의 예제에서 행의 길이를 명시하고, 열의 길이를 생략하면 컴파일할 때 오류가 발생한다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-25_PointerConcept.md b/_posts/Language/C/2023-12-04-25_PointerConcept.md new file mode 100644 index 000000000000..5f69b117a92d --- /dev/null +++ b/_posts/Language/C/2023-12-04-25_PointerConcept.md @@ -0,0 +1,165 @@ +--- +layout: single +title: Chapter 25 포인터의 개념 +date: 2023-12-04 18:51:09 +09:00 +categories: + - Language +tags: + - C +excerpt: 포인터의 개념에 관한 글입니다. +toc: true +--- + +# 1 주소값의 이해 + +- 데이터의 주소값 + +> 데이터의 주소값이란 해당 데이터가 저장된 메모리의 시작 주소를 의미한다. + +>C 언어에서는 이러한 주소값을 1바이트 크기의 메모리 공간으로 나누어 표현한다. +예를 들어, int형 데이터는 4바이트의 크기를 가지지만, +int형 데이터의 주소값은 시작 주소 1바이트만을 가리킨다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/e322e216-7b18-418f-829a-ae28db873a76) + +# 2 포인터(pointer) + +- 포인터(pointer) + +> C 언어에서 포인터(pointer)란 메모리의 주소값을 저장하는 변수를 의미하며, +> 포인터 변수라고도 부른다. + +> char형 변수가 문자를 저장하고, +> int형 변수가 정수를 저장하는 것처럼 포인터는 주소값을 저장한다. + +- 예제 + +```c +int n = 100;   // 변수의 선언 +int *ptr = &n; // 포인터의 선언 +``` + +>다음 그림은 위의 예제에서 사용된 변수와 포인터가 메모리에서 +어떻게 저장되는지를 보여주는 예제이다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/ce6e3641-6b38-4923-b039-af079049a063) + +## 2.1 포인터 연산자 + +>C 언어에서 포인터와 연관되어 사용되는 연산자는 다음과 같다. + +1. 주소 연산자(&) + +2. 참조 연산자(*) + +### 2.1.1 주소 연산자(&) + +>주소 연산자는 변수의 이름 앞에 사용하여, 해당 변수의 주소값을 반환한다. +'&'기호는 앰퍼샌드(ampersand)라고 읽으며, 번지 연산자라고도 불린다. + +### 2.1.2 참조 연산자(*) + +>참조 연산자는 포인터의 이름이나 주소 앞에 사용하여, +>포인터에 가리키는 주소에 저장된 값을 반환한다. + +>C 언어에서 '*'기호는 사용하는 위치에 따라 다양한 용도로 사용된다. +이항 연산자로 사용하면 곱셈 연산으로 사용되며, +포인터의 선언 시나 메모리에 접근할 때도 사용된다. + +## 2.2 포인터의 선언 + +>C 언어에서 포인터는 다음 문법에 따라 선언한다. + +- 문법 + +```c +타입* 포인터이름;   +``` + +>타입이란 포인터가 가리키고자 하는 변수의 타입을 명시한다. +포인터 이름은 포인터가 선언된 후에 포인터에 접근하기 위해 사용된다. + +>포인터를 선언한 후 참조 연산자(*)를 사용하기 전에 포인터는 반드시 먼저 초기화되어야 한다. +그렇지 않으면 의도하지 않은 메모리의 값을 변경하게 되기 때문이다. +따라서 C 컴파일러는 초기화하지 않은 포인터에 참조 연산자를 사용하면 오류를 발생시킨다. + +>따라서 다음과 같이 포인터의 선언과 동시에 초기화를 함께 하는 것이 좋다. + +- 문법 + +```c +타입* 포인터이름 = &변수이름; +또는 +타입* 포인터이름 = 주소값; +``` + +## 2.3 포인터의 참조 + +>C 언어에서 선언된 포인터는 참조 연산자(*)를 사용하여 참조할 수 있다. + +>다음 예제는 포인터의 주소값과 함께 포인터가 가리키고 있는 +>주소값의 데이터를 참조하는 예제이다. + +- 예제 + +```c +int x = 7;        // 변수의 선언 +int *ptr = &x;    // 포인터의 선언 +int *pptr = &ptr; // 포인터의 참조 +``` + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/9584b102-8aaf-41be-92bc-f444d8705be1) + +- 예제 + +```c +int num01 = 1234; +double num02 = 3.14;   +int* ptr_num01 = &num01; +double* ptr_num02 = &num02;   +``` + +```c +① printf("포인터의 크기는 %d입니다.\n", sizeof(ptr_num01)); +② printf("포인터 ptr_num01이 가리키고 있는 주소값은 %#x입니다.\n", ptr_num01); +③ printf("포인터 ptr_num02가 가리키고 있는 주소값은 %#x입니다.\n", ptr_num02); +printf("포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n", *ptr_num01); +printf("포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %f입니다.\n", *ptr_num02); +``` + +- 실행 결과 + +```c +포인터의 크기는 8입니다. +포인터 ptr_num01이 가리키고 있는 주소값은 0x7c255e4입니다. +포인터 ptr_num02가 가리키고 있는 주소값은 0x7c255e8입니다. +포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 1234입니다. +포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 3.140000입니다. +``` + +>위 예제의 ①번 라인에서는 sizeof 연산자를 사용하여 포인터 변수의 크기를 구하고 있다. + +>포인터 변수는 메모리에서 변수의 위치를 나타내는 주소를 다루는 변수이므로, +>그 크기는 일반적으로 CPU에 따라 결정된다. +따라서 32비트 CPU에서는 1워드(word)의 크기가 4바이트이므로, +포인터 변수의 크기 또한 4바이트가 될 것이다. + +>하지만 이러한 포인터 변수의 크기는 컴파일러로 컴파일할 때 그 크기까지 직접 명시할 수 있다. +따라서 포인터 변수의 크기는 CPU의 종류와 컴파일할 때 +사용된 컴파일러의 정책에 따라서 달라질 수 있다. + +>또한, ②번과 ③번 라인에서처럼 포인터가 가리키는 +>변수의 타입에 따라 포인터의 타입도 같이 바꿔주고 있다. +포인터의 타입은 참조 연산자를 통해 값을 참조할 때, +참조할 메모리의 크기를 알려주는 역할을 하기 때문이다. + +>다음 그림은 char형 포인터와 int형 포인터가 각각 메모리 상에서 +>해당 타입의 변수를 가리키는 것을 보여준다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/2217656e-9e96-4995-9446-f14c820cf68e) + +>워드(word)란 CPU가 한 번에 처리할 수 있는 데이터의 크기이다. +1바이트는 8비트이므로 32비트 시스템에서는 32비트 / 8비트 = 4, +즉 4바이트가 1워드(word)로 처리된다. +64비트 시스템에서는 64비트 / 8비트 = 8, +즉 8바이트가 1워드(word)로 처리된다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-26_PointerOperation.md b/_posts/Language/C/2023-12-04-26_PointerOperation.md new file mode 100644 index 000000000000..8016dac65bda --- /dev/null +++ b/_posts/Language/C/2023-12-04-26_PointerOperation.md @@ -0,0 +1,103 @@ +--- +layout: single +title: Chapter 26 포인터 연산 +date: 2023-12-04 18:51:42 +09:00 +categories: + - Language +tags: + - C +excerpt: 포인터 연산에 관한 글입니다. +toc: true +--- + +# 1 포인터 연산 + +> 포인터는 값을 증가시키거나 감소시키는 등의 제한된 연산만을 할 수 있다. + +>C 언어의 포인터 연산에는 다음과 같은 규칙이 있다. + +1. 포인터끼리의 덧셈, 곱셈, 나눗셈은 아무런 의미가 없다. + +2. 포인터끼리의 뺄셈은 두 포인터 사이의 상대적 거리를 나타낸다. + +3. 포인터에 정수를 더하거나 뺄 수는 있지만, 실수와의 연산은 허용하지 않는다. + +4. 포인터끼리 대입하거나 비교할 수 있다. + +>다음 예제는 타입에 따른 포인터 연산의 증가값을 비교하는 예제이다. + +- 예제 + +```c +char* ptr_char = 0; +int* ptr_int = NULL; +double* ptr_double = 0x00;   + +printf("포인터 ptr_char가 현재 가리키고 있는 주소값은 %#x입니다.\n", ptr_char); +printf("포인터 ptr_int가 현재 가리키고 있는 주소값은 %#x입니다.\n", ptr_int); +printf("포인터 ptr_double이 현재 가리키고 있는 주소값은 %#x입니다.\n", ptr_double);   + +printf("포인터 ptr_char가 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n", ++ptr_char); +printf("포인터 ptr_int가 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n", ++ptr_int); +printf("포인터 ptr_double이 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n", ++ptr_double);   +``` + +- 실행 결과 + +```c +포인터   ptr_char가 현재 가리키고 있는 주소값은 0입니다. +포인터    ptr_int가 현재 가리키고 있는 주소값은 0입니다. +포인터 ptr_double이 현재 가리키고 있는 주소값은 0입니다. +포인터   ptr_char가 1 증가 후에 가리키고 있는 주소값은 0x1입니다. +포인터    ptr_int가 1 증가 후에 가리키고 있는 주소값은 0x4입니다. +포인터 ptr_double이 1 증가 후에 가리키고 있는 주소값은 0x8입니다. +``` + +>위의 예제에서 모든 포인터에 저장된 초기 주소값은 0x00 이다. +하지만 1을 증가시키는 포인터 연산 후 포인터가 가리키고 있는 주소는 +각각의 포인터 타입에 따라 달라진다. +그 증가 폭은 포인터가 가리키는 변수의 타입의 크기와 같게 된다. + +![포인터 연산](https://tcpschool.com/lectures/img_c_pointer_calculation.png) + +>예를 들어, int형 포인터의 증가폭은 int형 타입의 크기인 4바이트만큼 증가하게 된다. +이 법칙은 포인터의 뺄셈에서도 똑같이 적용된다. + +> 다음 예제는 포인터끼리의 비교 연산과 대입 연산을 보여주는 예제이다. + +- 예제 + +```c +int num01 = 10; +int num02 = 20; +int *ptr_num01 = &num01; +int *ptr_num02 = &num02;   + +if (ptr_num01 != ptr_num02) // 포인터끼리의 비교 연산 +{ +    printf("포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n", *ptr_num01); +    printf("포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %d입니다.\n", *ptr_num02); +    printf("포인터 ptr_num01과 ptr_num02는 현재 다른 주소를 가리키고 있습니다.\n\n"); +    ptr_num02 = ptr_num01; // 포인터끼리의 대입 연산 +}   + +printf("포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 %d입니다.\n", *ptr_num01); +printf("포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 %d입니다.\n", *ptr_num02);   + +if (ptr_num01 == ptr_num02) // 포인터끼리의 비교 연산 +{ +    printf("포인터 ptr_num01과 ptr_num02는 현재 같은 주소를 가리키고 있습니다.\n"); +} +``` + +- 실행 결과 + +```c +포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 10입니다. +포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 20입니다. +포인터 ptr_num01과 ptr_num02는 현재 다른 주소를 가리키고 있습니다. + +포인터 ptr_num01이 가리키고 있는 주소에 저장된 값은 10입니다. +포인터 ptr_num02가 가리키고 있는 주소에 저장된 값은 10입니다. +포인터 ptr_num01과 ptr_num02는 현재 같은 주소를 가리키고 있습니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-27_HowToForwardArgument.md b/_posts/Language/C/2023-12-04-27_HowToForwardArgument.md new file mode 100644 index 000000000000..10a13298f819 --- /dev/null +++ b/_posts/Language/C/2023-12-04-27_HowToForwardArgument.md @@ -0,0 +1,110 @@ +--- +layout: single +title: Chapter 27 인수 전달 방법 +date: 2023-12-04 18:52:21 +09:00 +categories: + - Language +tags: + - C +excerpt: 변수의 유효 범위에 관한 글입니다. +toc: true +--- +# 1 인수 전달 방법 + +- 인수(argument) + +>인수(argument)란 함수가 호출될 때 함수로 값을 전달해주는 값을 의미한다. + +>함수를 호출할 때에는 함수에 필요한 데이터를 인수(argument)로 전달해 줄 수 있다. +>함수에 인수를 전달하는 방법에는 크게 다음과 같이 두 가지 방법이 있다. + +1. 값에 의한 전달(call by value) + +2. 참조에 의한 전달(call by reference) + +## 1.1 값에 의한 전달(call by value) + +- 값에 의한 전달(call by value) + +>값에 의한 전달(call by value) 방법이란 인수로 전달되는 변수가 가지고 있는 값을 +>함수 내의 매개변수에 복사하는 방식을 의미한다. + +> 이렇게 복사된 값으로 초기화된 매개변수는 전달된 변수와는 완전히 별개의 변수가 된다. +> 따라서 함수 내에서의 매개변수 조작은 인수로 전달되는 변수에 아무런 영향을 미치지 않는다. + +- 예제 + +```c +#include    +void local(int);   + +int main(void) +{ +    int var = 10; +    printf("변수 var의 초깃값은 %d입니다.\n", var);   + +    local(var); +    printf("local() 함수 호출 후 변수 var의 값은 %d입니다.\n", var); +    return 0; +}   + +void local(int num) +{ +    num += 10; +} +``` + +- 실행 결과 + +```c +변수 var의 초기값은 10입니다. +local() 함수 호출 후 변수 var의 값은 10입니다. +``` + +>위의 예제에서 local() 함수의 매개변수 num은 인수로 변수 var의 값을 전달받는다. +>따라서 함수 내에서 매개변수 num의 값을 아무리 변경하더라도 +>원래 인수로 전달된 변수 var의 값은 절대 변경되지 않는다. + +## 1.2 참조에 의한 전달(call by reference) + +- 참조에 의한 전달(call by reference) + +>참조에 의한 전달(call by reference) 방법이란 인수로 변수의 값을 전달하는 것이 아닌, +>해당 변수의 주소 값을 전달하는 방식을 의미한다. + +>즉 함수의 매개변수에 인수로 전달된 변수의 원래 주소값을 저장하는 것이다. +>이 방식을 사용하면 인수로 전달된 변수의 값을 함수 내에서 변경할 수 있게 된다. + +- 예제 + +```c +#include    +void local(int*); + +int main(void) +{ +    int var = 10; +    printf("변수 var의 초깃값은 %d입니다.\n", var);   + +    local(&var); +    printf("local() 함수 호출 후 변수 var의 값은 %d입니다.\n", var); +    return 0; +}   + +void local(int* num) +{ +    *num += 10; +} +``` + +- 실행 결과 + +```c +변수 var의 초기값은 10입니다. +local() 함수 호출 후 변수 var의 값은 20입니다. +``` + +>위의 예제에서 local() 함수의 매개변수 num은 인수로 변수 var의 주소값을 전달받는다. +따라서 함수 내에서 매개변수 num의 값을 변경하면, +원래 인수인 변수 var의 값도 같이 변경된다. + diff --git a/_posts/Language/C/2023-12-04-28_VariousPointers.md b/_posts/Language/C/2023-12-04-28_VariousPointers.md new file mode 100644 index 000000000000..84cb7634acbd --- /dev/null +++ b/_posts/Language/C/2023-12-04-28_VariousPointers.md @@ -0,0 +1,166 @@ +--- +layout: single +title: Chapter 28 다양한 포인터 +date: 2023-12-04 18:53:11 +09:00 +categories: + - Language +tags: + - C +excerpt: 다양한 포인터에 관한 글입니다. +toc: true +--- + +# 1 다양한 포인터 + +## 1.1 포인터의 포인터 + +- 포인터의 포인터 + +>포인터의 포인터란 포인터 변수를 가리키는 포인터를 의미한다. +>참조 연산자(*)를 두 번 사용하여 표현하며, 이중 포인터라고도 부른다. + +>다음 그림은 포인터와 포인터의 포인터와의 동작 상 차이점을 보여주고 있다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/37cc2625-89df-4c38-9e13-9365d34ec85d) + +>다음 예제는 포인터의 포인터를 선언하고, 포인터의 포인터를 이용한 접근 방법을 보여주고 있다. + +- 예제 + +```c +int num = 10;              // 변수 선언 +int* ptr_num = #       // 포인터 선언 +int** pptr_num = &ptr_num; // 포인터의 포인터 선언   + +printf("변수 num가 저장하고 있는 값은 %d입니다.\n", num); +printf("포인터  ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n", *ptr_num); +printf("포인터의 포인터 pptr_num가 가리키는 주소에 저장된 포인터가 가리키는 주소에 저장된 값은 %d입니다.\n", **pptr_num); +``` + +- 실행 결과 + +```c +변수 num가 저장하고 있는 값은 10입니다. +포인터 ptr_num가 가리키는 주소에 저장된 값은 10입니다. +포인터의 포인터 pptr_num가 가리키는 주소에 저장된 포인터가 가리키는 주소에 저장된 값은 10입니다. +``` + +## 1.2 void 포인터(void pointer) + +- void 포인터(void pointer) + +>void 포인터(void pointer)란 일반적인 포인트 변수와는 달리 +>대상이 되는 데이터의 타입을 명시하지 않은 포인터를 의미한다. + +>따라서 변수, 함수, 포인터 등 어떠한 값도 가리킬 수 있지만, +> 포인터 연산이나 메모리 참조와 같은 작업은 할 수 없다. + +>즉 void 포인터는 주소값을 저장하는 것 이외에는 아무것도 할 수 없는 포인터이다. +>또한, void 포인터를 사용할 때에는 반드시 먼저 사용하고자 하는 타입으로 +>명시적 타입 변환 작업을 거친 후에 사용해야 한다. + +>다음 예제는 void 포인터의 선언 및 void 포인터를 이용한 접근 방법을 보여주고 있다. + +- 예제 + +```c +int num = 10;         // 변수 선언 +void* ptr_num = # // void 포인터 선언   + +printf("변수 num가 저장하고 있는 값은 %d입니다.\n", num); +printf("void 포인터 ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n", *(int*)ptr_num);   + +*(int*)ptr_num = 20;  // void 포인터를 통한 메모리 접근   +printf("void 포인터 ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n", *(int*)ptr_num); +``` + +- 실행 결과 + +```c +변수 num가 저장하고 있는 값은 10입니다. +void 포인터 ptr_num가 가리키는 주소에 저장된 값은 10입니다. +void 포인터 ptr_num가 가리키는 주소에 저장된 값은 20입니다. +``` + +> 위의 예제처럼 void 포인터는 사용할 때마다 명시적 타입 변환을 하고 난 뒤에 사용해야 한다. + +## 1.3 함수 포인터(function pointer) + +>프로그램에서 정의된 함수는 프로그램이 실행될 때 모두 메인 메모리에 올라가게 된다. +>이때 함수의 이름은 메모리에 올라간 함수의 시작 주소를 가리키는 +>포인터 상수(constant pointer)가 된다. + +- 함수 포인터(function pointer) + +>함수 포인터(function pointer)란 함수의 시작 주소를 가리키는 포인터 상수를 의미한다. + +>함수 포인터의 포인터 타입은 함수의 반환값과 매개변수에 의해 결정된다. +>즉 함수의 원형을 알아야만 해당 함수에 맞는 함수 포인터를 만들 수 있다. + +- 함수 원형 + +```c +void func (int, int); +``` + +> 위와 같은 함수 원형을 가지는 함수에 대한 함수 포인터는 다음과 같다. + +- 함수 포인터 + +```c +void (*ptr_func) (int, int); +``` + +>함수 포인터 사용시 연산자의 우선순위 때문에 +>반드시 *ptr_func 부분을 괄호(())로 둘러싸야 한다. + +>함수 포인터는 다음 예제처럼 함수를 또 다른 함수의 인수로 전달할 때 유용하게 사용된다. + +- 예제 + +```c +double (*calc)(double, double) = NULL; // 함수 포인터 선언 +double result = 0;   +double num01 = 3, num02 = 5; +char oper = '*';   + +switch (oper) +{ +    case '+': +        calc = add; +        break; +    case '-': +        calc = sub; +        break; +    case '*': +        calc = mul; +        break; +    case '/': +        calc = div; +        break; +    default: +        puts("사칙연산(+, -, *, /)만을 지원합니다."); +}   + +result = calculator(num01, num02, calc); +printf("사칙 연산의 결과는 %lf입니다.\n", result); +``` + +- 실행 결과 + +```c +사칙 연산의 결과는 15.000000입니다. +``` + +>위의 예제는 함수 포인터를 사용하여 변수 oper의 값에 따라 +>4개의 사칙연산 함수 중 하나를 선택한다. +>이렇게 선택된 함수는 함수 포인터를 사용하여 +>calculator() 함수에 인수로 전달되게 된다. + +## 1.4 널 포인터(null pointer) + +- 널 포인터(null pointer) + +>널 포인터(null pointer)란 0이나 NULL을 대입하여 초기화한 포인터를 의미한다. +>널 포인터는 아무것도 가리키지 않는 포인터라는 의미이다. + diff --git a/_posts/Language/C/2023-12-04-29_PointerToArrayRelationships.md b/_posts/Language/C/2023-12-04-29_PointerToArrayRelationships.md new file mode 100644 index 000000000000..2f70b6ac0aeb --- /dev/null +++ b/_posts/Language/C/2023-12-04-29_PointerToArrayRelationships.md @@ -0,0 +1,97 @@ +--- +layout: single +title: Chapter 29 포인터와 배열의 관계 +date: 2023-12-04 18:53:52 +09:00 +categories: + - Language +tags: + - C +excerpt: 포인터와 배열의 관계에 관한 글입니다. +toc: true +--- + +# 1 포인터와 배열의 관계 + +>포인터와 배열은 매우 긴밀한 관계를 맺고 있으며, 어떤 부분에서는 서로를 대체할 수도 있다. + +>배열의 이름은 그 값을 변경할 수 없는 상수라는 점을 제외하면 포인터와 같다. +>따라서 배열의 이름은 포인터 상수(constant pointer)이다. + +- 포인터 상수(constant pointer) + +>포인터 상수(constant pointer)란 포인터 변수가 가리키고 있는 주소 값을 변경할 수 없는 포인터를 의미한다. + +- 상수 포인터(pointer to constant) + +>상수 포인터(pointer to constant)란 상수를 가르키는 포인터를 의미한다. + +- 예제 + +```c +int arr[3] = {10, 20, 30}; // 배열 선언 +int* ptr_arr = arr;        // 포인터에 배열의 이름을 대입함   + +printf("배열의 이름을 이용하여 배열 요소에 접근 : %d %d %d\n", arr[0], arr[1], arr[2]); +printf("     포인터를 이용하여 배열 요소에 접근 : %d %d %d\n", ptr_arr[0], ptr_arr[1], ptr_arr[2]);   +printf("배열의 이름을 이용한 배열의 크기 계산 : %d\n", sizeof(arr)); +printf("     포인터를 이용한 배열의 크기 계산 : %d\n", sizeof(ptr_arr)); +``` + +- 실행결과 + +```c +배열의 이름을 이용하여 배열 요소에 접근 : 10 20 30 +     포인터를 이용하여 배열 요소에 접근 : 10 20 30 +배열의 이름을 이용한 배열의 크기 계산 : 12 +     포인터를 이용한 배열의 크기 계산 : 8 +``` + +>위의 예제에서는 포인터에 이름을 대입한 후, 해당 포인터를 배열의 이름처럼 사용한다. +>이처럼 C 언어에서는 배열의 이름을 포인터처럼 사용할 수 있을 뿐만 아니라, +>포인터를 배열의 이름처럼 사용할 수도 있다. + +>하지만 배열의 크기를 계산할 때에는 배열의 이름과 포인터 사이에 차이가 발생한다. +>배열의 이름을 이용한 크기 계산에서는 +>배열의 크기가 int형 배열 요소 3개의 크기인 12바이트로 제대로 출력된다. +>하지만 포인터를 이용한 크기 계산에서는 배열의 크기가 아닌 +>포인터 변수 자체의 크기가 출력되는 차이가 있다. + +# 2 배열의 포인터 연산 + +>다음 예제는 배열의 이름을 포인터처럼 사용하는 예제이다. +>배열의 이름으로 포인터 연산을 수행하여 각각의 배열 요소에 접근한다. + +- 예제 + +```c +int arr[3] = {10, 20, 30}; // 배열 선언   +printf("          배열의 이름을 이용하여 배열 요소에 접근 : %d %d %d\n", arr[0], arr[1], arr[2]); +printf("배열의 이름으로 포인터 연산을 해 배열 요소에 접근 : %d %d %d\n", *(arr+0), *(arr+1), *(arr+2)); +``` + +- 실행 결과 + +```c +          배열의 이름을 이용하여 배열 요소에 접근 : 10 20 30 +배열의 이름으로 포인터 연산을 해 배열 요소에 접근 : 10 20 30 +``` + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/e445ea69-dbb2-47ae-8e4e-43079dcae800) + +>따라서 배열의 이름과 포인터 사이에는 다음과 같은 공식이 성립한다. + +- 공식 + +```c +arr이 배열의 이름이거나 포인터이고 n이 정수일 때, +arr[n] == *(arr + n) +``` + +>위의 공식은 1차원 배열뿐만 아니라 다차원 배열에서도 언제나 성립한다. + +>배열의 관계된 연산을 할 때는 언제나 +>배열의 크기를 넘어서는 접근을 하지 않도록 주의해야 한다. +>포인터 연산을 이용하여 계산하다가 배열의 크기를 넘어서는 접근을 하는 경우, +>C 컴파일러는 어떠한 오류도 발생시키지 않는다. +>다만 잘못된 결과만을 반환하므로 +>C 언어로 프로그래밍할 때에는 언제나 배열의 크기에도 주의해야 한다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-30_PointerArrayAndArrayPointers.md b/_posts/Language/C/2023-12-04-30_PointerArrayAndArrayPointers.md new file mode 100644 index 000000000000..2fd1775419be --- /dev/null +++ b/_posts/Language/C/2023-12-04-30_PointerArrayAndArrayPointers.md @@ -0,0 +1,196 @@ +--- +layout: single +title: Chapter 30 포인터 배열과 배열 포인터 +date: 2023-12-04 18:54:29 +09:00 +categories: + - Language +tags: + - C +excerpt: 포인터 배열과 배열 포인터에 관한 글입니다. +toc: true +--- + +# 1 포인터 배열 + +- 포인터 배열 + +>포인터 배열이란 배열 요소로 포인터 변수를 가지는 배열을 의미한다. + +>즉, 포인터 변수를 저장할 수 있는 배열을 의미한다. + +>다음 예제는 세 개의 int형 포인터 변수를 저장할 수 있는 포인터 배열을 선언하는 예제이다. + +- 예제 + +```c +int i, arr_len; +int num01 = 10, num02 = 20, num03 = 30; +int* arr[3] = {&num01, &num02, &num03}; // int형 포인터 배열 선언   + +arr_len = sizeof(arr)/sizeof(arr[0]); +for (i = 0; i < arr_len; i++) +{ +    printf("%d\n", *arr[i]); +} +``` + +- 실행 결과 + +```c +10 +20 +30 +``` + +> 다음 그림은 위의 예제에서 사용된 포인터 배열이  +> 메모리 상에서 어떻게 동작하는지를 보여준다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/00a9bb46-8133-45c6-b0d4-a8710ded7331) + +# 2 배열 포인터 + +- 배열 포인터 + +> 배열 포인터란 배열을 가리킬 수 있는 포인터를 의미한다. + +>배열의 이름은 그 값을 변경할 수 없는 상수라는 점을 제외하면 포인터와 같다. +이렇게 배열 이름이 있는데도 따로 배열 포인터를 정의하여  +사용하는 이유는 2차원 이상의 배열을 가리킬 때 포인터를 통해 +배열과 같은 인덱싱을 할 수 있도록 하기 위함이다. +즉, 포인터를 배열처럼 사용하기 위해서 배열 포인터를 정의하여 사용한다. +따라서 배열 포인터는 1차원 배열에서는 아무런 의미가 없으며, +2차원 이상의 배열에서만 의미를 가진다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/8b901fdf-1e70-466d-8067-4a112886764a) + +>위의 그림에서 보면 2차원 배열의 배열 이름 arr는 부분 배열 arr[0]와 같은 곳을 가리킨다. +2차원 배열의 배열 이름으로 포인터 연산을 하면 배열의 행 단위로 이동하게 된다. +즉, (arr+1)은  arr[1]과 같은 곳을 가리키게 된다. + +>다음 예제는 2차원 배열에서 각 부분 배열의 시작 주소가 가리키는 +>메모리에 저장된 데이터를 출력하는 예제이다. + +- 예제 + +```c +int arr[2][3] = { +    {10, 20, 30}, +    {40, 50, 60} +};   + +printf("%d\n", *arr[0]); +printf("%d\n", *arr[1]); +``` + +- 실행 결과 + +```c +10 +40 +``` + +>2차원 배열에서는 포인터 연산 시 증가하는 값이 행의 길이에 따라 차이를 보이게 된다. +2차원 배열의 행의 길이란 부분 배열의 크기를 의미하며, 다음 수식으로 구할 수 있다. + +- 수식 + +```c +sizeof(arr[0]) / sizeof(타입) +``` + +>다음 예제에서 포인터 연산 시 증감하는 값의 크기는 +>int형 타입의 크기인 4바이트에 배열 행의 길이인 3를 곱한 12바이트가 된다. + +- 예제 + +```c +int arr[2][3]; +``` + +>따라서 위의 예제에서 배열 이름 arr의 타입은 정확하게 다음과 같이 정의할 수 있다. + +1. 배열의 이름 arr는 int형 데이터를 가리키는 배열 포인터이다. + +2. 이 배열 포인터는 포인터 연산 시 증감하는 값의 크기가 12바이트이다. + +>따라서 위의 예제에서 배열 arr를 가리키는 배열 포인터는 다음과 같이 선언할 수 있다. + +- 예제 + +```c +int (*pArr)[3]; +``` + +>또한, 위 예제의 배열 포인터는 다음과 같은 배열들을 가리킬 수 있다. + +- 예제 + +```c +int arr01[2][3]; +int arr02[3][3]; +int arr03[4][3]; +... +``` + +>다음 예제는 배열 포인터를 사용하여 배열과 같은 +>인덱싱 방법으로 배열 요소를 참조하는 예제이다. + +- 예제 + +```c +int arr[2][3] =             // 배열의 선언 +{ +    {10, 20, 30}, +    {40, 50, 60} +}; + +int (*pArr)[3] = arr;       // 배열 포인터의 선언   + +printf("%d\n", arr[1][1]);  // 배열 이름으로 참조 +printf("%d\n", pArr[1][1]); // 배열 포인터로 참조 +``` + +- 실행 결과 + +```c +50 +50 +``` + +# 3 포인터 배열과 배열 포인터의 구분 + +>배열 포인터에서 괄호(())를 생략하면 전혀 다른 의미가 된다. + +- 예제 + +```c +1. int (*pArr)[3]; +2. int* pArr[3]; +``` + +>위의 예제 중에서 첫 번째는 int형 데이터를 저장할 수 있는 +>2차원 배열을 가리키는 배열 포인터이다. +하지만 두 번째는 int형 데이터를 가리킬 수 있는 포인터 변수를 모아 놓은 +배열을 가리키는 포인터 배열이 된다. + +>따라서 괄호의 유무가 중요하다. + +# 4 main() 함수의 인수 전달 + +>main() 함수는 프로그램이 실행되면 제일 먼저 자동으로 호출되는 함수이다. +이러한 main() 함수도 함수이기 때문에 인수를 전달받을 수도 있고, 반환값을 가질 수도 있다. + +>C 언어의 main() 함수의 원형은 다음과 같다. + +- 원형 + +```c +void(또는 int) main(int argc, char *argv[]); +``` + +>C 언어의 main() 함수의 첫 번째 인수는 int형 변수인 argc로  +>main() 함수에 인수로 전달되는 문자열의 개수를 명시한다. + +>두 번째 인수는 char형 포인터 배열인 argv로  +>main() 함수에 인수로 전달된 각각의 문자열이 저장된 배열을 가리킨다. + diff --git a/_posts/Language/C/2023-12-04-31_MemoryStructure.md b/_posts/Language/C/2023-12-04-31_MemoryStructure.md new file mode 100644 index 000000000000..9c0c1bd575f0 --- /dev/null +++ b/_posts/Language/C/2023-12-04-31_MemoryStructure.md @@ -0,0 +1,74 @@ +--- +layout: single +title: Chapter 31 메모리의 구조 +date: 2023-12-04 18:55:15 +09:00 +categories: + - Language +tags: + - C +excerpt: 메모리의 구조에 관한 글입니다. +toc: true +--- + +# 1 메모리의 구조 + +>프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드(load)되어야 한다. +>또한, 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다. + +>따라서 컴퓨터의 운영체제는 프로그램의 실행을 위해 다양한 메모리 공간을 제공하고 있다. +>프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 다음과 같다. + +1. 코드(code) 영역 + +2. 데이터(data) 영역 + +3. 스택(stack) 영역 + +4. 힙(heap) 영역 + +>다음 그림은 운영체제가 제공하는 메모리 공간을 표현하고 있다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/3bfcd042-482a-4034-9255-996ad800f281) + +## 1.1 코드(code) 영역 + +- 코드(code) 영역 + +>메모리의 코드(code) 영역이란 실행할 프로그램의 코드가 저장되는 영역으로 +>텍스트(code) 영역을 의미한다. + +>CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 된다. + +## 1.2 데이터(data) 영역 + +- 데이터(data) 영역 + +>메모리의 데이터(data) 영역이란 +>프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역을 의미한다. + +>데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다. + +## 1.3 스택(stack) 영역 + +- 스택(stack) 영역 + +>메모리의 스택(stack) 영역이란 +>함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역을 의미한다. + +>스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다. +이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다. + +>스택 영역은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다. +이러한 스택은 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작하므로, +가장 늦게 저장된 데이터가 가장 먼저 인출된다. +스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다. + +## 1.4 힙(heap) 영역 + +- 힙(heap) 영역 + +>메모리의 힙(heap) 영역이란 사용자가 직접 관리할 수 있는 +>'그리고 해야만 하는' 메모리 영역을 의미한다. + +>힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다. +힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다. diff --git a/_posts/Language/C/2023-12-04-32_StackFrame.md b/_posts/Language/C/2023-12-04-32_StackFrame.md new file mode 100644 index 000000000000..32c90d42155f --- /dev/null +++ b/_posts/Language/C/2023-12-04-32_StackFrame.md @@ -0,0 +1,94 @@ +--- +layout: single +title: Chapter 32 스택 프레임 +date: 2023-12-04 18:55:47 +09:00 +categories: + - Language +tags: + - C +excerpt: 스택 프레임에 관한 글입니다. +toc: true +--- + +# 1 스택 프레임(stack frame) + +>메모리의 스택(stack) 영역은 함수의 호출과 관계되는 +>지역 변수와 매개변수가 저장되는 영역이다. +스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다. + +>함수가 호출되면 스택에는 함수의 매개변수, +>호출이 끝난 뒤 돌아갈 반환 주소값, +>함수에서 선언된 지역 변수 등이 저장된다. + +- 스택 프레임(stack frame) + +>스택 프레임(stack frame)이란 스택 영역에 차례대로 저장되는 함수의 호출 정보를 의미한다. + +>이러한 스택 프레임 덕분에 함수의 호출이 모두 끝난 뒤에, +>해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다. + +## 1.1 스택 프레임의 동작 방식 + +- 예제 + +```c +int main(void) +{ +    func1();  // func1() 호출 +    return 0; +} + +void func1() +{ +    func2();  // func2() 호출 +} + +void func2() +{ + +} +``` + +>다음 그림은 위 예제 코드에서 함수 호출에 의한 스택 프레임의 변화를 보여주고 있다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/591611af-d2c2-45bd-bd49-f87b9b55aa6f) + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/5d0e8a98-fe8e-4538-b9da-55e58059f317) + +Step 1. 프로그램이 실행되면, 가장 먼저 main() 함수가 호출되어 +main() 함수의 스택 프레임이 스택에 저장된다. + +Step 2. func1() 함수를 호출하면 해당 함수의 매개변수, 반환 주소값, +지역 변수 등의 스택 프레임이 스택에 저장된다. + +Step 3. func2() 함수를 호출하면 해당 함수의 스택 프레임이 추가로 스택에 저장된다. + +Step 4. func2() 함수의 모든 작업이 완료되어 반환되면, +func2() 함수의 스택 프레임만이 스택에서 제거된다. + +Step 5. func1() 함수의 호출이 종료되면, +func1() 함수의 스택 프레임이 스택에서 제거된다. + +Step 6. main() 함수의 모든 작업이 완료되면, +main() 함수의 스택 프레임이 스택에서 제거되면서 프로그램이 종료된다. + +>이처럼 스택은 가장 나중에 저장된 데이터가 가장 먼저 인출되는 방식으로 동작한다. +이러한 방식을 후입선출(LIFO, Last-In First-Out) 방식이라고 한다. +이때 스택은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다. + +#### 스택 오버플로우(stack overflow) + +>함수의 재귀 호출이 무한히 반복되면,  +>해당 프로그램은 스택 오버플로우(stack overflow)에 의해 종료된다. + +>만약 재귀 호출이 무한히 반복되면, +>위 그림에서 Step 3 이후로는 재귀 호출에 의한 스택 프레임이 계속해서 쌓여만 갈 것이다. +이렇게 스택의 모든 공간을 다 차지하고 난 후 더 이상의 여유 공간이 없을 때 +또 다시 스택 프레임을 저장하게 되면, 해당 데이터는 스택 영역을 넘어가서 저장되게 된다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/b2254cc1-87f8-41b8-8ad6-de08d10904df) + +>이렇게 해당 스택 영역을 넘어가도 데이터가 저장될 수 있으면, +>해당 프로그램은 오동작을 하게 되거나 보안상의 크나큰 취약점을 가지게 된다. +따라서 C 언어에서는 실행 중인 프로그램에서 스택 오버플로우가 발생하면, +에러를 발생하고 곧바로 강제 종료시킨다. diff --git a/_posts/Language/C/2023-12-04-33_DynamicMemoryAllocation.md b/_posts/Language/C/2023-12-04-33_DynamicMemoryAllocation.md new file mode 100644 index 000000000000..69c5eb590e50 --- /dev/null +++ b/_posts/Language/C/2023-12-04-33_DynamicMemoryAllocation.md @@ -0,0 +1,203 @@ +--- +layout: single +title: Chapter 33 메모리의 동적 할당 +date: 2023-12-04 18:56:13 +09:00 +categories: + - Language +tags: + - C +excerpt: 메모리의 동적 할당에 관한 글입니다. +toc: true +--- + +# 1 메모리의 동적 할당(dynamic allocation) + +>데이터 영역과 스택 영역에 할당되는 메모리의 크기는 +> 컴파일 타임(compile time)에 미리 결정된다. +하지만 힙 영역의 크기는 프로그램이 실행되는 도중인 +런 타임(run time)에 사용자가 직접 결정하게 된다. + +- 메모리의 동적 할당(dynamic allocation) + +>메모리의 동적 할당(dynamic allocation)이란 런 타임에 메모리를 할당받는 것을 의미한다. + +## 1.1 malloc() 함수 + +>malloc() 함수는 프로그램이 실행 중일 때 +>사용자가 직접 힙 영역에 메모리를 할당할 수 있게 해준다. + +>malloc() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +void *malloc(size_t size);   +``` + +>malloc() 함수는 인수로 할당받고자 하는 메모리의 크기를 바이트 단위로 전달받는다. +이 함수는 전달받은 메모리 크기에 맞고, 아직 할당되지 않은 적당한 블록을 찾는다. +이렇게 찾은 블록의 첫 번째 바이트를 가리키는 주소값을 반환한다. + +>힙 영역에 할당할 수 있는 적당한 블록이 없을 때에는 널 포인터를 반환한다. +주소값을 반환받기 때문에 힙 영역에 할당된 +메모리 공간으로 접근하려면 포인터를 사용해야 한다. + +>malloc() 함수의 원형에서 볼 수 있는 size_t 타입은 부호없는 정수이다. + +## 1.2 free() 함수 + +>free() 함수는 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수이다. +데이터 영역이나 스택 영역에 할당되는 메모리의 크기는 +컴파일 타임에 결정되어, 프로그램이 실행되는 내내 고정된다. +하지만 메모리의 동적 할당으로 힙 영역에 생성되는 메모리의 크기는 런 타임 내내 변화된다. +따라서 free() 함수를 사용하여 다 사용한 메모리를 해제해 주지 않으면, +메모리가 부족해지는 현상이 발생할 수 있다. + +- 메모리 누수(memory leak) + +>메모리 누수(memory leak)란 사용이 끝난 메모리를 해제하지 않아서 메모리가 부족해지는 현상을 의미한다. + +>free() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +void free(void *ptr); +``` + +>free() 함수는 인수로 해제하고자 하는 메모리 공간을 가리키는 포인터를 전달받는다. +인수의 타입이 void형 포인터로 선언되어 있으므로, +어떠한 타입의 포인터라도 인수로 전달될 수 있다. + +>다음 예제는 크기가 고정된 배열이 아닌 런 타임에 크기가 결정되는 배열을 생성하는 예제이다. + +- 예제 + +```c +ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당   +if (ptr_arr == NULL) // 메모리의 동적 할당이 실패할 경우 +{ +    printf("메모리의 동적 할당에 실패했습니다.\n"); +    exit(1); +}   + +printf("동적으로 할당받은 메모리의 초깃값은 다음과 같습니다.\n"); +for (i = 0; i < arr_len; i++) +{ +    printf("%d ", ptr_arr[i]); +} + +free(ptr_arr);       // 동적으로 할당된 메모리의 반환   +``` + +- 실행 결과 + +```c +동적으로 할당받은 메모리의 초기값은 다음과 같습니다. +0 0 0 +``` + +## 1.3 calloc() 함수 + +>calloc() 함수는 malloc() 함수와 마찬가지로 힙 영역에 메모리를 동적으로 할당해주는 함수이다. +이 함수가 malloc() 함수와 다른 점은 할당하고자 하는 메모리의 크기를 +두 개의 인수로 나누어 전달받는 점이다. + +>또한, calloc() 함수는 메모리를 할당받은 후에 +>해당 메모리의 모든 비트값을 전부 0으로 초기화해준다. +calloc() 함수도 malloc() 함수와 마찬가지로 free() 함수를 통해 +할당받은 메모리를 해제해 주어야 한다. + +>calloc() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +void *calloc(size_t nmemb, size_t size); +``` + +>calloc() 함수의 첫 번째 인수는 메모리 블록의 개수를 나타내며, +>두 번째 인수는 각 블록의 바이트 수를 나타낸다. +따라서 calloc() 함수는 힙 영역에 +size 크기의 메모리 블록을 nmemb개 할당받을 수 있도록 요청한다. + +>앞선 예제에서 사용한 malloc() 함수와 다음 예제의 calloc() 함수는 똑같은 동작을 수행한다. + +- 예제 + +```c +1. ptr_arr = (int*) malloc(arr_len * sizeof(int)); +2. ptr_arr = (int*) calloc(arr_len, sizeof(int)); +``` + +## 1.4 realloc() 함수 + +>realloc() 함수는 이미 할당된 메모리의 크기를 바꾸어 재할당할 때 사용하는 함수이다. + +>realloc() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +void *realloc(void *ptr, size_t size); +``` + +>realloc() 함수의 첫 번째 인수는 +>크기를 바꾸고자 하는 메모리 공간을 가리키는 포인터를 전달받는다. +두 번째 인수로는 해당 메모리 공간에 재할당할 크기를 전달한다. +따라서 첫 번째 인수로 NULL이 전달되면, malloc() 함수와 정확히 같은 동작을 하게 된다. + +>다음 예제는 런 타임에 크기가 결정된 배열의 크기를 +>realloc() 함수를 사용해 다시 한 번 늘려주는 예제이다. + +- 예제 + +```c +ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당   +if (ptr_arr == NULL) // 메모리의 동적 할당이 실패할 경우 +{ +    printf("메모리의 동적 할당에 실패했습니다.\n"); +    exit(1); +}   + +printf("동적으로 할당받은 메모리의 초깃값은 다음과 같습니다.\n"); +for (i = 0; i < arr_len; i++) +{ +    printf("%d ", ptr_arr[i]); +} + +total_len = arr_len + add_len; +ptr_arr = (int*) realloc(ptr_arr, (total_len * sizeof(int))); // 메모리의 추가 할당 +if (ptr_arr == NULL) // 메모리의 추가 할당에 실패할 경우 +{ +    printf("메모리의 추가 할당에 실패했습니다.\n"); +    exit(1); +}   + +printf("\n추가로 할당받은 메모리의 초깃값은 다음과 같습니다.\n"); +for (i = 0; i < total_len; i++) +{ +    printf("%d ", ptr_arr[i]); +} + +free(ptr_arr); // 동적으로 할당된 메모리의 반환 +``` + +- 실행 결과 + +```c +동적으로 할당받은 메모리의 초기값은 다음과 같습니다. +0 0 0  +추가로 할당받은 메모리의 초기값은 다음과 같습니다. +0 0 0 0 0  +``` + +>realloc() 함수는 만약 기존의 메모리 위치에 충분한 공간이 있다면 +>바로 이어서 추가 메모리 공간을 할당해준다. +하지만 기존의 메모리 위치에 충분한 공간이 없으면 +메모리의 다른 공간에 기존의 데이터를 복사한 후, +이어서 추가 메모리 공간을 할당하게 된다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-34_BasicIO.md b/_posts/Language/C/2023-12-04-34_BasicIO.md new file mode 100644 index 000000000000..a50198e33778 --- /dev/null +++ b/_posts/Language/C/2023-12-04-34_BasicIO.md @@ -0,0 +1,89 @@ +--- +layout: single +title: Chapter 34 기본적인 입출력 +date: 2023-12-04 18:56:55 +09:00 +categories: + - Language +tags: + - C +excerpt: 기본적인 입출력에 관한 글입니다. +toc: true +--- + +# 1 기본적인 입출력 + +>C 언어에서는 기억장치에 저장되는 파일을 다루는 것과 +마찬가지 방식으로 입출력 장치를 다룬다. +따라서 키보드, 모니터와 같은 대부분의 콘솔 장치도  +C 프로그램에서는 자동으로 열리는 파일처럼 다뤄진다. +C 언어에서는 stdin 표준 스트림을 통해 입력 장치를 다루며, +stdout 표준 스트림을 통해 출력 장치를 다루게 된다. + +## 1.1 스트림(stream) + +>C 프로그램은 파일이나 콘솔의 입출력을 직접 다루지 않고, +스트림(stream)이라는 것을 통해 다룬다. + +- 스트림(stream) + +>스트림(stream)이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다. +즉, 스트림은 운영체제에 의해 생성되는 가상의 연결 고리를 의미한다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/9db0fd13-ca5b-4866-948e-bef07a41a283) + +>C 언어에서 파일과의 연결을 위한 스트림은 사용자가 직접 생성하고 소멸시켜야 한다. +하지만 콘솔 장치에 대한 스트림은 프로그램 실행 시 자동으로 생성되며, +프로그램 종료 시 자동으로 소멸한다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/5b75a5c5-f2d2-4251-8ebe-ee8fb2006613) + +>C 언어에서 기본적으로 제공되는 표준 스트림(standard stream)은 다음과 같다. + +![스크린샷(757)](https://github.com/EunChong999/EunChong999/assets/136239807/21f61ecc-bc9c-46e9-8671-65fb76a41b5c) + +## 1.2 EOF(End Of File) + +>운영체제에서 파일의 끝을 탐지하는 방법은 운영체제마다 약간씩 다르다. +하지만 C 언어는 운영체제와 상관없이, +파일의 끝에 도달했을 때 언제나 특별한 값을 반환하도록 한다. +그 값을 EOF(End Of File)라고 하며, 실제로 이 값은 -1을 나타낸다. + +>파일뿐만 아니라 키보드를 통한 입력 시에도 입력의 끝을 알려주는 방법이 필요하다. +대부분의 유닉스(UNIX) 시스템에서는 +라인의 시작 위치에서 Ctrl+D를 누르면 EOF를 발생시킬 수 있다. +윈도우 명령창에서는 해당 라인의 어디에서든 Ctrl+Z를 누르고 나서 +Enter를 누르면 EOF를 발생시킬 수 있다. + +>다음 예제는 사용자가 EOF를 입력할 때까지 계속해서 영문자를 한 문자씩 입력받는 예제이다. + +- 예제 + +```c +#include +int main(void) +{ +    char ch; +    printf("EOF가 입력될 때까지 영문자를 계속 입력받습니다 :\n"); +    printf("(윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다)\n"); + +    while ((ch = getchar()) != EOF) +    { +        putchar(ch); +    } +    return 0; +} +``` + +- 실행 결과 + +```c +EOF가 입력될 때까지 영문자를 계속 입력받습니다 :  +(윈도우에서 EOF의 강제 발생은 Ctrl+Z를 누르고 나서 Enter를 누르면 됩니다) +a +a +b +b +-1 +-1 +^Z +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-35_CharacterInputOutputFunction.md b/_posts/Language/C/2023-12-04-35_CharacterInputOutputFunction.md new file mode 100644 index 000000000000..6a302dbea374 --- /dev/null +++ b/_posts/Language/C/2023-12-04-35_CharacterInputOutputFunction.md @@ -0,0 +1,113 @@ +--- +layout: single +title: Chapter 35 문자 입출력 함수 +date: 2023-12-04 18:58:06 +09:00 +categories: + - Language +tags: + - C +excerpt: 문자 입출력 함수에 관한 글입니다. +toc: true +--- +# 1 단일 문자 입력 함수 + +>C 언어에서 하나의 문자를 입력할 때에는 getchar() 함수나 fgetc() 함수를 사용한다. + +## 1.1 getchar() 함수 + +>getchar() 함수는 표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수이다. + +>getchar() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int getchar(void); +``` + +## 1.2 fgetc() 함수 + +>fgetc() 함수는 getchar() 함수와 마찬가지로  +>표준 입력 스트림(stdin)인 키보드로부터 하나의 문자를 입력받는 함수이다. + +>하지만 getchar() 함수와는 달리 문자를 입력받을 스트림을 +>인수로 전달하여 직접 지정할 수 있다. +따라서 fgetc() 함수는 키보드뿐만 아니라 파일을 통해서도 문자를 입력받을 수 있다. + +>fgetc() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int fgetc(FILE *stream); +``` + +# 2 단일 문자 출력 함수 + +>C 언어에서 하나의 문자를 출력할 때에는 putchar() 함수나 fputc() 함수를 사용한다. + +## 2.1 putchar() 함수 + +>putchar() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수이다. + +>putchar() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int putchar(int c); +``` + +## 2.2 fputc() 함수 + +>fputc() 함수는 putchar() 함수와 마찬가지로 +>표준 출력 스트림(stdout)인 모니터에 하나의 문자를 출력하는 함수이다. + +>하지만 putchar() 함수와는 달리 문자를 출력할 스트림을 +>인수로 전달하여 직접 지정할 수 있다. +따라서 fputc() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있다. + +>fputc() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int fputc(int c, FILE *stream); +``` + +>다음 예제는 단일 문자 입출력 함수를 사용하여, +>'x'문자가 입력될 때까지 계속해서 영문자를 입력받고 출력하는 예제이다. + +- 예제 + +```c +#include    +int main(void) +{ +    char ch; +    printf("x가 입력될 때까지 영문자를 계속 입력받습니다 :\n");   + +    while ((ch = getchar()) != 'x') +    { +        putchar(ch); +    }   +    printf("x를 입력하셨습니다.\n");   +    return 0; +} +``` + +- 실행 결과 + +```c +x가 입력될 때까지 영문자를 계속 입력받습니다 :  +c +c +d +d +x +x를 입력하셨습니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-36_String.md b/_posts/Language/C/2023-12-04-36_String.md new file mode 100644 index 000000000000..7815ce87619a --- /dev/null +++ b/_posts/Language/C/2023-12-04-36_String.md @@ -0,0 +1,82 @@ +--- +layout: single +title: Chapter 36 문자열 +date: 2023-12-04 18:59:00 +09:00 +categories: + - Language +tags: + - C +excerpt: 문자열에 관한 글입니다. +toc: true +--- +# 1 문자열(string) + +- 문자열 상수(string constant) + +>C 언어에서 문자열 상수(string constant)란 큰따옴표("")를 사용해 표현되는 문자열을 의미한다. + +>상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, +>문자열의 내용 또한 변경할 수 없기 때문이다. + +- 문자열(string) + +>C 언어에서 문자열(string)이란 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미한다. + +>따라서 문자형 배열을 선언하면 이 배열이 곧 문자열 변수가 된다. + +>다음 예제는 문자열 상수 및 변수를 선언하는 여러 방법을 보여주는 예제이다. + +- 예제 + +```c +char str01[] = "This is a string.";    // 크기를 지정하지 않은 문자열 변수 선언 +char str02[7] = "string";              // 크기를 지정한 문자열 변수 선언 + +printf("이것은 문자열 상수입니다.\n"); // 문자열 상수 +printf("문자열 str01에 저장되어 있는 문자열은 \"%s\"입니다.\n", str01); +printf("문자열 str02에 저장되어 있는 문자열은 \"%s\"입니다.\n", str02);   +``` + +- 실행 결과 + +```c +이것은 문자열 상수입니다. +문자열 str01에 저장되어 있는 문자열은 "This is a string."입니다. +문자열 str02에 저장되어 있는 문자열은 "string"입니다. +``` + +>printf() 함수에서 사용된 '%s'는 문자열을 표현하기 위한 입출력 서식 문자이다. + +# 2 널(NULL) 문자 + +>문자형 배열로 선언된 문자열 변수는 문자열의 끝을 프로그램에 따로 알려주어야 한다. +그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레깃값을 구분할 수 있다. + +>따라서 C 언어에서는 문자열에 속한 데이터가 끝나면, +>문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다. +이 문자를 널(NULL) 문자라고 하며, '\0'으로 표시하고 아스키코드값은 0이다. + +>다음 예제는 널 문자를 이용하여 널 문자를 제외한 문자열의 길이를 계산하여 출력해주는 예제이다. + +- 예제 + +```c +int str_len = 0; +char str[] = "string"; + +while (str[str_len] != '\0') // 널 문자가 나올 때까지 길이를 증가함 +{ +    str_len++; +} +printf("이 문자열의 길이는 %d입니다.\n", str_len); +``` + +- 실행 결과 + +```c +이 문자열의 길이는 6입니다. +``` + +>다음 그림은 위 예제에서 사용된 문자열이 메모리 상에 어떻게 저장되어 있는지를 보여준다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/d5868786-d696-420d-b075-429488d7b303) diff --git a/_posts/Language/C/2023-12-04-37_StringIOFunction.md b/_posts/Language/C/2023-12-04-37_StringIOFunction.md new file mode 100644 index 000000000000..423be28bdea4 --- /dev/null +++ b/_posts/Language/C/2023-12-04-37_StringIOFunction.md @@ -0,0 +1,105 @@ +--- +layout: single +title: Chapter 37 문자열 입출력 함수 +date: 2023-12-04 18:59:30 +09:00 +categories: + - Language +tags: + - C +excerpt: 문자열 입출력 함수에 관한 글입니다. +toc: true +--- + +# 1 문자열 입력 함수 + +>C 언어에서 문자열을 입력할 때에는 fgets() 함수를 사용한다. + +## 1.1 fgets() 함수 + +>fgets() 함수는 키보드뿐만 아니라 파일에서도 문자열을 입력받을 수 있는 함수이다. + +>fgets() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +char *fgets(char * restrict s, int n, FILE * restrict stream);   +``` + +>fgets() 함수의 첫 번째 인수는 입력받는 문자열을 +>저장하기 위해 선언한 배열의 시작 주소를 전달한다. +두 번째 인수로는 입력받을 수 있는 문자열의 최대 길이를 전달하고, +마지막 인수로는 문자열을 입력받을 스트림을 전달한다. + +# 2 문자열 출력 함수 + +>C 언어에서 문자열을 입력할 때에는 puts()함수나 fputs() 함수를 사용한다. + +## 2.1 puts() 함수 + +>puts() 함수는 표준 출력 스트림(stdout)인 모니터에 하나의 문자열을 출력하는 함수이다. +이 함수는 모니터에 문자열을 출력한 다음에 자동으로 줄을 바꿔준다. + +>puts() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int puts(const char *s);   +``` + +>puts() 함수는 인수로 출력할 문자열을 가리키는 포인터를 전달한다. + +## 2.2 fputs() 함수 + +>fputs() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수이다. +이 함수는 puts() 함수와는 달리 문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다. + +>fputs() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int fputs(const char * restrict s, FILE * restrict stream); +``` + +>fputs() 함수의 첫 번째 인수는 출력할 문자열을 가리키는 포인터를 전달한다. +>두 번째 인수로는 문자열을 출력할 스트림을 전달한다. + +>다음 예제는 문자열 입출력 함수를 사용하여,  +>사용자가 입력한 문자열을 그대로 출력하는 예제이다. + +- 예제 + +```c +#include +int main(void) +{ +    char str[100]; + +    fputs("문자열을 입력해 주세요 :\n", stdout); +    fgets(str, sizeof(str), stdin); +    puts("입력하신 문자열 : "); +    puts(str); +    fputs("입력하신 문자열 : ", stdout); +    fputs(str, stdout); +    return 0; +} +``` + +- 실행 결과 + +```c +문자열을 입력해 주세요 :  +C언어 문자열 입출력 +입력하신 문자열 :  +C언어 문자열 입출력 + +입력하신 문자열 : C언어 문자열 입출력 +``` + +>위의 예제에서 puts() 함수는 문자열을 출력한 후에 자동으로 줄 바꿈을 해준다. +하지만 fputs() 함수는 문자열을 출력한 후에 줄 바꿈을 하지 않는다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-38_StringProcessingFunction.md b/_posts/Language/C/2023-12-04-38_StringProcessingFunction.md new file mode 100644 index 000000000000..50745e87220b --- /dev/null +++ b/_posts/Language/C/2023-12-04-38_StringProcessingFunction.md @@ -0,0 +1,371 @@ +--- +layout: single +title: Chapter 38 문자열 처리 함수 +date: 2023-12-04 19:00:21 +09:00 +categories: + - Language +tags: + - C +excerpt: 문자열 처리 함수에 관한 글입니다. +toc: true +--- + +# 1 문자열 처리 함수 + +>C 언어에서 문자열은 마지막에 널 문자를 가지는 문자형 배열로 표현되며, +>기본 타입에는 포함되지 않는다. +따라서 C 컴파일러가 기본 타입을 위해 +제공하는 다양한 연산자를 자유롭게 사용할 수 없다. + +>이 때문에 C 언어는 문자열을 처리하기 위한 다양한 함수를 별도로 제공하고 있다. +C 언어에서 제공하는 대표적인 문자열 처리 함수는 다음과 같다. + +1. strlen() 함수 + +2. strcat(), strncat() 함수 + +3. strcpy(), strncpy() 함수 + +4. strcmp(), strncmp() 함수 + +5. atoi(), atol(), atoll(), atof() 함수 + +6. toupper(), tolower() 함수 + + +## 1.1 strlen() 함수 + +>strlen() 함수는 인수로 전달된 문자열의 길이를 반환하는 함수이다. +이때 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다. + +>strlen() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +size_t strlen(const char *s);  +``` + +>다음 예제는 strlen() 함수를 이용하여 문자열의 길이를 구하는 예제이다. + +- 예제 + +```c +char str[] = "C언어";   +printf("이 문자열의 길이는 %d입니다.\n", strlen(str)); +``` + +- 실행 결과 + +```c +이 문자열의 길이는 7입니다. +``` + +>utf-8 인코딩 환경에서 한글은 한 문자당 3바이트로 처리된다. + +## 1.2 strcat()함수와 strncat() 함수 + +>strcat()함수와 strncat() 함수는 하나의 문자열에 다른 문자열을 연결해주는 함수이다. + +>strcat() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +char *strcat(char * restrict s1, const char * restrict s2);   +``` + +>strcat() 함수의 첫 번째 인수로 전달된 문자열은 기준 문자열이 된다. +두 번째 인수로 전달된 추가하고자 하는 문자열의 복사본이 기준 문자열 뒤에 추가된다. + +>위의 원형에서 볼 수 있는 restrict 키워드는 +>포인터의 선언에서만 사용할 수 있는 C99부터 추가된 키워드이다. +포인터를 선언할 때 이 키워드를 명시하면, +컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시한다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/72507d7f-4be9-48fd-bc1c-53713cd3dbdf) + +>이때 기준 문자열이 저장된 배열의 공간이 충분하지 않으면, +>배열을 채우고 남은 문자들이 배열 외부로 흘러넘칠 수 있다. +이러한 현상을 배열 오버플로우(overflow)라고 한다. +배열 오버플로우 현상을 방지하기 위해서는 strcat() 함수 대신에 +strncat() 함수를 사용하는 것이 좋다. + +>strncat() 함수는 strcat() 함수와 하는 일은 같지만, +>세 번째 인수로 추가할 문자열의 최대 길이를 지정할 수 있다. +이 함수는 널 문자를 만나거나, +추가하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 +도달할 때까지 추가를 계속한다. + +>strncat() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +char *strncat(char * restrict s1, const char * restrict s2, size_t n);   +``` + +- 예제 + +```c +char str01[20] = "C language is "; // 널 문자를 포함하여 15문자 +char str02[] = "Cool! and funny!";   +//strcat(str01, str02);   // 이 부분의 주석 처리를 삭제한 후 실행시키면 배열 오버플로우우가 발생함 +strncat(str01, str02, 5); // 이렇게 최대 허용치를 설정해 놓으면 배열 오버플로우우에 대해서는 안전해짐 +puts(str01); +``` + +- 실행 결과 + +```c +C language is Cool! +``` + +>위의 예제에서는 우선 널 문자를 포함한 총 14바이트 크기의 문자열을 +>19바이트 크기의 배열에 저장한다. +그리고 그 문자열에 정확히 5바이트 크기의 문자열을 추가하는 예제이다. +이때 strncat() 함수가 아닌 strcat() 함수를 사용해도 괜찮지만, +만약 5바이트 이상의 문자열을 추가하려고 한다면 배열 오버플로우가 발생할 것이다. + +## 1.3 strcpy() 함수와 strncpy() 함수 + +>strcpy() 함수와 strncpy() 함수는 문자열을 복사하는 함수이다. + +>strcpy() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +char *strcpy(char * restrict s1, const char * restrict s2);   +``` + +>strcpy() 함수는 첫 번째 인수로 전달된 배열에, +>두 번째 인수로 전달된 문자열을 복사한다. +하지만 이때 첫 번째 인수로 전달된 배열의 크기가 복사할 문자열의 길이보다 작으면, +배열 오버플로우가 발생한다. +배열 오버플로우 현상을 방지하기 위해서는 strcpy() 함수 대신에  +strncpy() 함수를 사용하는 것이 좋다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/99883c4f-a851-4cfc-87c5-79a37b58b304) + +>strncpy() 함수는 strcpy() 함수와 하는 일은 같지만, +>세 번째 인수로 복사할 문자열의 최대 길이를 지정할 수 있다. +이 함수는 널 문자를 만나거나, +복사하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 +도달할 때까지 복사를 계속한다. + +>strncpy() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +char *strncpy(char * restrict s1, const char * restrict s2, size_t n);    +``` + +>다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 복사하는 예제이다. +이렇게 복사한 문자열의 마지막에는 반드시 널 문자를 삽입해 주어야만 +C 프로그램이 제대로 문자열로 인식할 수 있다. + +- 예제 + +```c +char str01[20] = "C is Cool!"; +char str02[11];   + +// str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임 +strncpy(str02, str01, sizeof(str02)-1); +str02[sizeof(str02)-1] = '\0'; // 이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음 +puts(str02); +``` + +- 실행 결과 + +```c +C is Cool! +``` + +>다음 예제는 strncpy() 함수를 이용하여 문자열의 일부분만을 수정하는 예제이다. +strncpy() 함수의 첫 번째 인수에 배열 이름을 이용한 포인터 연산을 사용하여  +수정을 시작할 지점을 지정할 수 있다. + +- 예제 + +```c +char str[20] = "C is cool!";   +strncpy(str+5, "nice", 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함 +puts(str); +``` + +- 실행 결과 + +```c +C is nice! +``` + +## 1.4 strcmp() 함수와 strncmp() 함수 + +>strcmp() 함수와 strncmp() 함수는 문자열의 내용을 비교하는 함수이다. + +>strcmp() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int strcmp(const char *s1, const char *s2);   +``` + +>strcmp() 함수는 인수로 두 개의 문자열 포인터를 전달받아, +>해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. +두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, +문자열의 맨 앞에서부터 순서대로 비교된다. + +>strcmp() 함수의 상황별 반환값은 다음과 같다. + +![스크린샷(758)](https://github.com/EunChong999/EunChong999/assets/136239807/ac5e1774-44b8-4594-be85-2d9b43150553) + +>strncmp() 함수는 strcmp() 함수와 하는 일은 같지만, +>세 번째 인수로 비교할 문자의 개수를 지정할 수 있다. +이 함수는 일치하지 않는 문자를 만나거나, +세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다. + +>strncmp() 함수의 원형은 다음과 같다. + +- 원형 + +```c +#include +int strncmp(const char *s1, const char *s2, size_t n);   +``` + +>다음 예제는 strcmp() 함수를 이용하여 두 문자열을 비교하는 예제이다. +strcmp() 함수는 문자열을 비교하는 함수이므로,  +문자를 비교할 때에는 관계연산자 '=='를 사용해야 한다. + +- 예제 + +```c +#include +#include    +int main(void) +{ +    char str[20]; +    char ch;   + +    while (1) +    { +        puts("미국의 수도를 입력하세요 :"); +        scanf("%s", str); +        if (strcmp(str, "워싱턴") == 0 || strcmp(str, "washington") == 0) // 문자열의 비교 +        { +            puts("정답입니다!"); +            break; +        } +        else +            puts("아쉽네요~"); +        fflush(stdin);   + +        puts("\n이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!"); +        puts("계속 도전하고자 하시면 Enter를 눌러주세요!"); +        scanf("%c", &ch);   +        if (ch == 'q') // 문자의 비교 +        { +            break; +        } +        fflush(stdin); +    } +    return 0; +} +``` + +- 실행 결과 + +```c +미국의 수도를 입력하세요 :  +뉴욕 +아쉽네요~ + +이 프로그램을 끝내고자 한다면 'q'를 눌러주세요! +계속 도전하고자 하시면 Enter를 눌러주세요! + +미국의 수도를 입력하세요 :  +워싱턴 +정답입니다! +``` + +## 1.5 atoi(), atol(), atoll(), atof() 함수 + +>이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수이다. + +>atoi(), atol(), atoll(), atof() 함수의 원형은 각각 다음과 같다. + +- 원형 + +```c +#include +int atoi(const char *nptr);            // int형 정수로 변환함. +long int atol(const char *nptr);       // long형 정수로 변환함. +long long int atoll(const char *nptr); // long long형 정수로 변환함. +double atof(const char *nptr);         // double형 실수로 변환함.   +``` + +>다음 예제는 숫자로 이루어진 문자열을 숫자로 변환하여, +> 곱셈 연산을 수행하는 예제이다. + +- 예제 + +```c +char str01[] = "10"; +char str02[] = "20";   +printf("문자열을 숫자로 변환해서 곱한 값은 %d입니다.\n", atoi(str01) * atoi(str02)); +``` + +- 실행 결과 + +```c +문자열을 숫자로 변환해서 곱한 값은 200이다. +``` + +## 1.6 toupper() 함수와 tolower() 함수 + +>이 함수들은 인수로 전달된 문자열의 영문자를 +>모두 대문자나 소문자로 변환시켜주는 함수이다. + +>toupper(), tolower() 함수의 원형은 각각 다음과 같다. + +- 원형 + +```c +#include +int toupper(int c); // 문자열의 모든 영문자를 대문자로 변환함. +int tolower(int c); // 문자열의 모든 영문자를 소문자로 변환함.   +``` + +>다음 예제는 문자열 내의 모든 영문자를 대문자로 변환하는 예제이다. + +- 예제 + +```c +int i, str_len; +char str[] = "Hello C World!";   +printf("원래 문자열 : %s\n", str); + +str_len = strlen(str); +for (i = 0; i < str_len; i++) +{ +    str[i] = toupper(str[i]); +} +printf("바뀐 문자열 : %s\n", str); +``` + +- 실행 결과 + +```c +원래 문자열 : Hello C World! +바뀐 문자열 : HELLO C WORLD! +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-39_BasicStructure.md b/_posts/Language/C/2023-12-04-39_BasicStructure.md new file mode 100644 index 000000000000..e878d21c80bb --- /dev/null +++ b/_posts/Language/C/2023-12-04-39_BasicStructure.md @@ -0,0 +1,267 @@ +--- +layout: single +title: Chapter 39 구조체의 기본 +date: 2023-12-04 19:01:09 +09:00 +categories: + - Language +tags: + - C +excerpt: 구조체의 기본에 관한 글입니다. +toc: true +--- + +# 1 구조체(structure type) + +- 구조체(structure type) + +>구조체(structure type)란 사용자가 C 언어의 기본 타입을 가지고 +>새롭게 정의할 수 있는 사용자 정의 타입을 의미한다. + +>구조체는 기본 타입만으로는 나타낼 수 없는 복잡한 데이터를 표현할 수 있다. + +>배열이 같은 타입의 변수 집합이라고 한다면, +>구조체는 다양한 타입의 변수 집합을 하나의 타입으로 나타낸 것이다. +이때 구조체를 구성하는 변수를  +구조체의 멤버(member) 또는 멤버 변수(member variable)라고 한다. + +## 1.1 구조체의 정의와 선언 + +>C 언어에서 구조체는 struct 키워드를 사용하여 다음과 같이 정의한다. + +- 문법 + +```c +struct 구조체이름 +{ +    멤버변수1의타입 멤버변수1의이름; +    멤버변수2의타입 멤버변수2의이름; +    ... +}; +``` + +>다음은 book이라는 이름의 구조체를 정의하는 그림이다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/18e39362-0630-4c39-9ff0-8a63445dae60) + +>struct라는 키워드를 사용하여 구조체의 시작을 알리고, +>구조체 이름인 book으로 구조체를 정의하고 있다. +중괄호 사이에 char titile[30], char author[30], int price와 같은 +변수들은 book의 멤버 변수들이다. +마지막 세이콜론은 구조체 정의를 종료한다는 의미이다. +이렇게 정의된 book 구조체는 사용자 정의 자료형이라고 한다. +이렇게 정의된 구조체 타입은 다음과 같이 구조체 변수로 선언하여 사용할 수 있다. + +- 문법 + +```c +struct 구조체이름 구조체변수이름; +``` + +- 예제 + +```c +struct book my_book; +``` + +>또한, 구조체의 정의와 구조체 변수의 선언을 동시에 할 수도 있다. + +- 문법 + +```c +struct 구조체이름 +{ +    멤버변수1의타입 멤버변수1의이름; +    멤버변수2의타입 멤버변수2의이름; +    ... +} 구조체변수이름; +``` + +- 예제 + +```c +struct book +{ +    char title[30]; +    char author[30]; +    int price; +} my_book; +``` + +## 1.2 typedef 키워드 + +>C 언어의 typedef 키워드는 이미 존재하는 타입에 새로운 이름을 붙일 때 사용한다. +구조체 변수를 선언하거나 사용할 때에는 +매번 struct 키워드를 사용하여 구조체임을 명시해야 한다. +하지만 typedef 키워드를 사용하여 구조체에 새로운 이름을 선언하면 +매번 struct 키워드를 사용하지 않아도 된다. + +>typedef 키워드를 사용하여 새로운 이름을 선언하는 방법은 다음과 같다. + +- 문법 + +```c +typedef struct 구조체이름 구조체의새로운이름; +``` + +- 예제 + +```c +typedef struct book TEXTBOOK; +``` + +>또한, 구조체의 정의와 typedef 선언을 동시에 할 수도 있다. + +- 문법 + +```c +typedef struct (구조체이름) +{ +    멤버변수1의타입 멤버변수1의이름; +    멤버변수2의타입 멤버변수2의이름; +    ... +} 구조체의새로운이름; +``` + +- 예제 + +```c +typedef struct { +    char title[30]; +    char author[30]; +    int price; +} TEXTBOOK; +``` + +>구조체의 정의와 typedef 선언을 동시에 할 때에는 구조체의 이름을 생략할 수 있다. + +## 1.3 구조체 멤버로의 접근 방법 + +>배열에서는 인덱스를 이용하여 배열 요소에 접근할 수 있다. +하지만 구조체에서 구조체 멤버로 접근하려고 할 때는 멤버 연산자(.)를 사용해야 한다. + +>구조체에서 구조체 멤버로의 접근 방법은 다음과 같다. + +- 문법 + +```c +구조체변수이름.멤버변수이름 +``` + +- 예제 + +```c +my_book.author +``` + +>구조체의 주소값과 구조체의 첫 번째 멤버 변수의 주소값은 언제나 같다. + +## 1.4 구조체 변수의 초기화 + +>구조체 변수를 초기화할 때에는 멤버 연산자(.)와 중괄호({})를 사용한다. + +>구조체 변수의 초기화 방법은 다음과 같다. + +- 문법 + +```c +구조체변수이름 = {.멤버변수1이름 = 초깃값, .멤버변수2이름 = 초깃값, ...}; +``` + +- 예제 + +```c +my_book = {.title = "HTML과 CSS", .author = "홍길동", .price = 28000}; +``` + +>이 방법을 사용하면 원하는 멤버 변수만을 초기화할 수 있다. +이때 멤버 변수가 정의된 순서와 초기화하는 순서는 아무런 상관이 없으며, +초기화하지 않은 멤버 변수는 0으로 초기화된다. + +>또한, 배열의 초기화와 같은 방법으로 구조체 변수를 초기화할 수도 있다. + +- 문법 + +```c +구조체변수이름 = {멤버변수1의초깃값, 멤버변수2의초깃값, ...}; +``` + +- 예제 + +```c +my_book = {"HTML과 CSS", "홍길동", 28000}; +``` + +>이때 구조체 정의에서 멤버 변수가 정의된 순서에 따라 차례대로 초깃값이 설정되며, +>나머지 멤버 변수는 0으로 초기화된다. + +>다음 예제는 두 가지 방법을 사용하여 각각 구조체 변수를 초기화하는 예제이다. + +- 예제 + +```c +#include    + +struct book +{ +    char title[30]; +    char author[30]; +    int price; +};   + +int main(void) +{ +    struct book my_book = {"HTML과 CSS", "홍길동", 28000}; +    struct book java_book = {.title = "Java language", .price = 30000};   + +    printf("첫 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", +        my_book.title, my_book.author, my_book.price); +    printf("두 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", +        java_book.title, java_book.author, java_book.price); +    return 0; +} +``` + +- 실행 결과 + +```c +첫 번째 책의 제목은 HTML과 CSS이고, 저자는 홍길동이며, 가격은 28000원입니다. +두 번째 책의 제목은 Java language이고, 저자는 이며, 가격은 30000원입니다. +``` + +>다음 예제는 구조체에 typedef 키워드를 사용하여 새로운 이름을 선언한 후 사용하는 예제이다. + +- 예제 + +```c +#include    + +typedef struct +{ +    char title[30]; +    char author[30]; +    int price; +}  TEXTBOOK;   + +int main(void) +{ +    TEXTBOOK my_book = {"HTML과 CSS", "홍길동", 28000}; +    TEXTBOOK java_book = {.title = "Java language", .price = 30000};   + +    printf("첫 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", +        my_book.title, my_book.author, my_book.price); +    printf("두 번째 책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", +        java_book.title, java_book.author, java_book.price); +    return 0; +} +``` + +- 실행 결과 + +```c +첫 번째 책의 제목은 HTML과 CSS이고, 저자는 홍길동이며, 가격은 28000원입니다. +두 번째 책의 제목은 Java language이고, 저자는 이며, 가격은 30000원입니다. +``` + +>위 예제의 실행 결과처럼 typedef 키워드를 사용하여 구조체에 +>새로운 이름을 선언한 후 사용해도 +>structr 키워드를 그대로 사용한 것과 같은 결과를 얻을 수 있다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-40_PointersAndStructures.md b/_posts/Language/C/2023-12-04-40_PointersAndStructures.md new file mode 100644 index 000000000000..fe919c8c8155 --- /dev/null +++ b/_posts/Language/C/2023-12-04-40_PointersAndStructures.md @@ -0,0 +1,133 @@ +--- +layout: single +title: Chapter 40 포인터와 구조체 +date: 2023-12-04 19:02:00 +09:00 +categories: + - Language +tags: + - C +excerpt: 포인터와 구조체에 관한 글입니다. +toc: true +--- + +# 1 구조체 배열 선언 + +>C 언어에서 배열의 요소가 될 수 있는 타입에는 제한이 없으므로, +>구조체 역시 배열의 한 요소가 될 수 있다. +이러한 구조체 배열을 선언하는 방법은 다른 타입의 배열을 선언하는 방법과 같다. +또한, 구조체 배열에서 각 배열 요소로 접근하는 방법도 +일반 배열의 접근 방법과 완전히 같다. + +>다음 예제는 구조체 배열의 선언 및 초기화를 보여주는 예제이다. + +- 예제 + +```c +struct book text_book[3] = +{ +    {"국어", "홍길동", 15000}, +    {"영어", "이순신", 18000}, +    {"수학1", "강감찬", 10000} +};   + +puts("각 교과서의 이름은 다음과 같습니다."); +printf("%s, %s, %s\n", text_book[0].title, text_book[1].title, text_book[2].title);   +``` + +- 실행 결과 + +```c +각 교과서의 이름은 다음과 같습니다. +국어, 영어, 수학1 +``` + +>위의 예제처럼 구조체 배열은 2차원 배열의 초기화 방법과 똑같은 방법으로 초기화할 수 있다. +또한, 멤버 연산자(.)를 사용하여 각 배열 요소의 멤버에 접근할 수 있다. + +>다음 그림은 위의 예제에서 사용된 구조체 배열 text_book의 메모리 상태를 보여준다. + +![image](https://github.com/EunChong999/EunChong999/assets/136239807/e313798e-979a-4515-95f0-6c02fb14984e) + +# 2 구조체를 가리키는 포인터 + +>구조체 변수를 가리키는 구조체 포인터는 다음과 같이 선언한다. + +- 문법 + +```c +struct 구조체이름* 구조체포인터이름; +``` + +- 예제 + +```c +struct book* ptr_my_book; +``` + +>배열의 경우와는 달리 구조체의 이름은 구조체를 가리키는 주소가 아니다. +따라서 포인터에 할당할 때에는 반드시 주소 연산자(&)를 사용해야 한다. + +>구조체 포인터를 이용하여 구조체의 멤버에 접근하는 방법에는 +>다음과 같이 두 가지 방법이 있다. + +1. 참조 연산자(*)를 이용하는 방법 + +2. 화살표 연산자(->)를 이용하는 방법 + +>참조 연산자를 이용하는 방법은 다음과 같다. + +- 문법 + +```c +(*구조체포인터).멤버변수이름 +``` + +- 예제 + +```c +(*ptr_my_book).author +``` + +>참조 연산자(*)는 멤버 연산자(.)보다 연산자 우선순위가 낮으므로 +>반드시 괄호(())를 사용해야 한다. + +>구조체의 멤버에 접근하기 위해서 화살표 연산자(->)를 사용할 수도 있다. +화살표 연산자의 앞쪽에는 구조체 포인터를, +뒤쪽에는 접근하고자 하는 구조체의 멤버 변수 이름을 사용하면 된다. + +- 문법 + +```c +구조체포인터 -> 멤버변수이름 +``` + + - 예제 + +```c +ptr_my_book -> author   +``` + +>위의 두 가지 방법은 완전히 같은 동작을 하며, +>일반적으로 화살표 연산자가 좀 더 많이 사용된다. + +- 예제 + +```c +struct book my_book = {"C언어 완전 해부", "홍길동", 35000}; +struct book* ptr_my_book; // 구조체 포인트 선언   + +ptr_my_book = &my_book;   + +strcpy((*ptr_my_book).title, "C언어 마스터"); // 참조 연산자(*)를 이용하는 방법 +strcpy(ptr_my_book->author, "이순신");        // 화살표 연산자(->)를 이용하는 방법 +my_book.price = 32000;                        // 구조체 변수을 이용한 직접 수정   + +printf("책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", +    my_book.title, my_book.author, my_book.price); +``` + +- 실행 결과 + +```c +책의 제목은 C 언어 마스터이고, 저자는 이순신이며, 가격은 32000원입니다. +``` \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md b/_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md new file mode 100644 index 000000000000..e46bf0c90de0 --- /dev/null +++ b/_posts/Language/C/2023-12-04-41_UtilizationOfStructures.md @@ -0,0 +1,196 @@ +--- +layout: single +title: Chapter 41 구조체의 활용 +date: 2023-12-04 19:02:36 +09:00 +categories: + - Language +tags: + - C +excerpt: 구조체의 활용에 관한 글입니다. +toc: true +--- + +# 1 함수와 구조체 + +>C 언어에서는 함수를 호출할 때 전달되는 인수나, +함수가 종료될 때 반환되는 반환값으로 구조체를 사용할 수 있다. +그 방식은 기본 타입과 완전히 같으며, +구조체를 가리키는 포인터나 구조체의 한 멤버 변수만을 사용할 수도 있다. + +>다음 예제는 구조체의 멤버 변수를 함수의 인수로 전달하는 예제이다. + +- 예제 + +```c +typedef struct +{ +    int savings; +    int loan; +} PROP;   + +int main(void) +{ +    int hong_prop; +    PROP hong = {10000000, 4000000};   + +    hong_prop = calcProperty(hong.savings, hong.loan); // 구조체의 멤버 변수를 함수의 인수로 전달함   + +    printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", +        hong.savings, hong.loan, hong_prop); +    return 0; +} +``` + +- 실행 결과 + +```c +홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다. +``` + +>위와 같이 구조체를 인수로 전달하는 방식은 함수가 +>원본 구조체의 복사본을 가지고 작업하므로 안전하다는 장점을 가진다. + +>다음 예제는 함수의 인수로 구조체의 주소를 직접 전달하는 예제이다. + +- 예제 + +```c +int hong_prop; +PROP hong = {10000000, 4000000};   + +hong_prop = calcProperty(&hong); // 구조체의 주소를 함수의 인수로 전달함.   +printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", hong.savings, hong.loan, hong_prop); +``` + +- 실행 결과 + +```c +홍길동의 재산은 적금 100원에 대출 4000000원을 제외한 총 -3999900원입니다. +``` + +>위와 같이 구조체 포인터를 인수로 전달하는 방식은 구조체의 복사본이 아닌 +>주소 하나만을 전달하므로 처리가 빠르다. +하지만 호출된 함수에서 원본 구조체에 직접 접근하므로 +원본 데이터의 보호 측면에서는 매우 위험하다. + +>따라서 다음 예제의 calcProperty() 함수처럼 const 키워드를 사용하여 +>함수에 전달된 인수를 함수 내에서는 직접 수정할 수 없도록 하는 것이 좋다. + +- 예제 + +```c +PROP prop; +int hong_prop;   + +prop = initProperty(); +hong_prop = calcProperty(&prop);   + +printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", prop.savings, prop.loan, hong_prop); +``` + +- 실행 결과 + +```c +홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다. +``` + +>위의 예제에서 initProperty() 함수는 반환값으로 구조체를 직접 반환한다. +기본적으로 C 언어의 함수는 한 번에 하나의 데이터만을 반환할 수 있다. +하지만 이렇게 구조체를 사용하면 여러 개의 데이터를 한 번에 반환할 수 있다. + +# 2 중첩된 구조체 + +>C 언어에서는 구조체를 정의할 때 멤버 변수로 또 다른 구조체를 포함할 수 있다. + +- 예제 + +```c +struct name +{ +    char first[30]; +    char last[30]; +};   +struct friends +{ +    struct name friend_name; +    char address[30]; +    char job[30]; +};   + +int main(void) +{ +    struct friends hong = +    { +        { "길동", "홍" }, +        "서울시 강남구 역삼동", +        "학생" +    };   + +    printf("%s\n\n", hong.address); +    printf("%s%s에게,\n", hong.friend_name.last, hong.friend_name.first); +    printf("그동안 잘 지냈니? 아직 %s이지?\n", hong.job); +    puts("공부 잘 하고, 다음에 꼭 한번 보자.\n잘 지내^^"); +    return 0; +}   +``` + +- 실행 결과 + +```c +서울시 강남구 역삼동 + +홍길동에게, +그동안 잘 지냈니? 아직 학생이지? +공부 잘 하고, 다음에 꼭 한번 보자. +잘 지내^^ +``` + +>위의 예제에서 friends 구조체는 또 다른 구조체인 name 구조체를 멤버 변수로 포함하고 있다. + +# 3 구조체의 크기 + +>일반적으로 구조체의 크기는 멤버 변수들의 크기에 따라 결정된다. +하지만 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하는 것은 아니다. + +- 예제 + +```c +typedef struct +{ +    char a; +    int b; +    double c; +} TYPESIZE;   + +int main(void) +{ +    puts("구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다."); +    printf("%d %d %d\n", sizeof(char), sizeof(int), sizeof(double));   + +    puts("구조체 TypeSize의 크기는 다음과 같습니다."); +    printf("%d\n", sizeof(TYPESIZE)); +    return 0; +} +``` + +- 실행 결과 + +```c +구조체 TYPESIZE의 각 멤버의 크기는 다음과 같습니다. +1 4 8 +구조체 TYPESIZE의 크기는 다음과 같습니다. +16 +``` + +>위의 예제에서 구조체 멤버 변수의 크기는 각각 1, 4, 8바이트이다. +하지만 구조체의 크기는 멤버 변수들의 크기 총합인 13바이트가 아니라 16바이트가 된다. + +#### 바이트 패딩(byte padding) + +구조체를 메모리에 할당할 때 컴파일러는 프로그램의 속도 향상을 위해 바이트 패딩(byte padding)이라는 규칙을 이용합니다. + +구조체는 다양한 크기의 타입을 멤버 변수로 가질 수 있는 타입입니다. + +하지만 컴파일러는 메모리의 접근을 쉽게 하기 위해 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞추게 됩니다. + +이것을 바이트 패딩이라고 하며, 이때 추가되는 바이트를 패딩 바이트(padding byte)라고 합니다. \ No newline at end of file diff --git a/_posts/Language/C/2023-12-04-42_CommonAndEnumeration.md b/_posts/Language/C/2023-12-04-42_CommonAndEnumeration.md new file mode 100644 index 000000000000..f6196ac1681a --- /dev/null +++ b/_posts/Language/C/2023-12-04-42_CommonAndEnumeration.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 42 공용체와 열거체 +date: 2023-12-04 19:03:17 +09:00 +categories: + - Language +tags: + - C +excerpt: 공용체와 열거체에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-43_ConsoleIO.md b/_posts/Language/C/2023-12-04-43_ConsoleIO.md new file mode 100644 index 000000000000..eb9f33177e69 --- /dev/null +++ b/_posts/Language/C/2023-12-04-43_ConsoleIO.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 43 콘솔 입출력 +date: 2023-12-04 19:03:54 +09:00 +categories: + - Language +tags: + - C +excerpt: 콘솔 입출력에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-44_FileIO.md b/_posts/Language/C/2023-12-04-44_FileIO.md new file mode 100644 index 000000000000..9797e8d8b0fa --- /dev/null +++ b/_posts/Language/C/2023-12-04-44_FileIO.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 44 파일 입출력 +date: 2023-12-04 19:04:22 +09:00 +categories: + - Language +tags: + - C +excerpt: 파일 입출력에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-45_FileIOFunction.md b/_posts/Language/C/2023-12-04-45_FileIOFunction.md new file mode 100644 index 000000000000..a06eaabfe197 --- /dev/null +++ b/_posts/Language/C/2023-12-04-45_FileIOFunction.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 45 파일 입출력 함수 +date: 2023-12-04 19:04:56 +09:00 +categories: + - Language +tags: + - C +excerpt: 파일 입출력 함수에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-46_Pre-processor.md b/_posts/Language/C/2023-12-04-46_Pre-processor.md new file mode 100644 index 000000000000..25fa358833e4 --- /dev/null +++ b/_posts/Language/C/2023-12-04-46_Pre-processor.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 46 선행처리기 +date: 2023-12-04 19:05:40 +09:00 +categories: + - Language +tags: + - C +excerpt: 선행처리기에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-47_MacroFunction.md b/_posts/Language/C/2023-12-04-47_MacroFunction.md new file mode 100644 index 000000000000..3891f7fb21f2 --- /dev/null +++ b/_posts/Language/C/2023-12-04-47_MacroFunction.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 47 매크로 함수 +date: 2023-12-04 19:06:13 +09:00 +categories: + - Language +tags: + - C +excerpt: 매크로 함수에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-48_Pre-definedMacro.md b/_posts/Language/C/2023-12-04-48_Pre-definedMacro.md new file mode 100644 index 000000000000..d8d97ff7e074 --- /dev/null +++ b/_posts/Language/C/2023-12-04-48_Pre-definedMacro.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 48 미리 정의된 매크로 +date: 2023-12-04 19:06:56 +09:00 +categories: + - Language +tags: + - C +excerpt: 미리 정의된 매크로에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-49_HeaderFiles.md b/_posts/Language/C/2023-12-04-49_HeaderFiles.md new file mode 100644 index 000000000000..c7b70e045c9f --- /dev/null +++ b/_posts/Language/C/2023-12-04-49_HeaderFiles.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 49 헤더 파일 +date: 2023-12-04 19:07:44 +09:00 +categories: + - Language +tags: + - C +excerpt: 헤더 파일에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-50_SplitCompilation.md b/_posts/Language/C/2023-12-04-50_SplitCompilation.md new file mode 100644 index 000000000000..0b9aa4372288 --- /dev/null +++ b/_posts/Language/C/2023-12-04-50_SplitCompilation.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 50 분할 컴파일 +date: 2023-12-04 19:08:20 +09:00 +categories: + - Language +tags: + - C +excerpt: 분할 컴파일에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-51_ConditionalCompilation.md b/_posts/Language/C/2023-12-04-51_ConditionalCompilation.md new file mode 100644 index 000000000000..210789cae961 --- /dev/null +++ b/_posts/Language/C/2023-12-04-51_ConditionalCompilation.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 51 조건부 컴파일 +date: 2023-12-04 19:08:50 +09:00 +categories: + - Language +tags: + - C +excerpt: 조건부 컴파일에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-52_ByteStorageOrder.md b/_posts/Language/C/2023-12-04-52_ByteStorageOrder.md new file mode 100644 index 000000000000..239a483940e3 --- /dev/null +++ b/_posts/Language/C/2023-12-04-52_ByteStorageOrder.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 52 바이트 저장 순서 +date: 2023-12-04 19:09:24 +09:00 +categories: + - Language +tags: + - C +excerpt: 바이트 저장 순서에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-53_BitOperation.md b/_posts/Language/C/2023-12-04-53_BitOperation.md new file mode 100644 index 000000000000..67a478395c7d --- /dev/null +++ b/_posts/Language/C/2023-12-04-53_BitOperation.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 53 비트 단위 연산 +date: 2023-12-04 19:10:00 +09:00 +categories: + - Language +tags: + - C +excerpt: 비트 단위 연산에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-54_RepresentationOfNegativeNumbers.md b/_posts/Language/C/2023-12-04-54_RepresentationOfNegativeNumbers.md new file mode 100644 index 000000000000..4d6b6840e917 --- /dev/null +++ b/_posts/Language/C/2023-12-04-54_RepresentationOfNegativeNumbers.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 54 음수의 표현 +date: 2023-12-04 19:10:35 +09:00 +categories: + - Language +tags: + - C +excerpt: 음수의 표현에 관한 글입니다. +toc: true +--- diff --git a/_posts/Language/C/2023-12-04-55_ExpressionsOfRealNumbers.md b/_posts/Language/C/2023-12-04-55_ExpressionsOfRealNumbers.md new file mode 100644 index 000000000000..234d3f8436ab --- /dev/null +++ b/_posts/Language/C/2023-12-04-55_ExpressionsOfRealNumbers.md @@ -0,0 +1,11 @@ +--- +layout: single +title: Chapter 55 실수의 표현 +date: 2023-12-04 19:11:25 +09:00 +categories: + - Language +tags: + - C +excerpt: 실수의 표현에 관한 글입니다. +toc: true +--- diff --git a/assets/images/404.png b/assets/images/404.png new file mode 100644 index 000000000000..3937b75ebdc8 Binary files /dev/null and b/assets/images/404.png differ diff --git a/assets/images/DEV.png b/assets/images/DEV.png new file mode 100644 index 000000000000..eb434154e3fd Binary files /dev/null and b/assets/images/DEV.png differ diff --git "a/\353\254\264\354\240\234 \355\214\214\354\235\274 1.canvas" "b/\353\254\264\354\240\234 \355\214\214\354\235\274 1.canvas" new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ "b/\353\254\264\354\240\234 \355\214\214\354\235\274 1.canvas" @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git "a/\353\254\264\354\240\234 \355\214\214\354\235\274 2.canvas" "b/\353\254\264\354\240\234 \355\214\214\354\235\274 2.canvas" new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ "b/\353\254\264\354\240\234 \355\214\214\354\235\274 2.canvas" @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git "a/\353\254\264\354\240\234 \355\214\214\354\235\274 3.canvas" "b/\353\254\264\354\240\234 \355\214\214\354\235\274 3.canvas" new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ "b/\353\254\264\354\240\234 \355\214\214\354\235\274 3.canvas" @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git "a/\353\254\264\354\240\234 \355\214\214\354\235\274.canvas" "b/\353\254\264\354\240\234 \355\214\214\354\235\274.canvas" new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ "b/\353\254\264\354\240\234 \355\214\214\354\235\274.canvas" @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git "a/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270 1.png" "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270 1.png" new file mode 100644 index 000000000000..5e07859e4746 Binary files /dev/null and "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270 1.png" differ diff --git "a/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270.png" "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270.png" new file mode 100644 index 000000000000..5e07859e4746 Binary files /dev/null and "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) - \353\263\265\354\202\254\353\263\270.png" differ diff --git "a/\354\212\244\355\201\254\353\246\260\354\203\267(753) 1.png" "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) 1.png" new file mode 100644 index 000000000000..30f3895af20d Binary files /dev/null and "b/\354\212\244\355\201\254\353\246\260\354\203\267(753) 1.png" differ diff --git "a/\354\212\244\355\201\254\353\246\260\354\203\267(753).png" "b/\354\212\244\355\201\254\353\246\260\354\203\267(753).png" new file mode 100644 index 000000000000..30f3895af20d Binary files /dev/null and "b/\354\212\244\355\201\254\353\246\260\354\203\267(753).png" differ