├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .idoc └── .filesStat.json ├── Dockerfile ├── LICENSE ├── README.md ├── assets ├── editer-01.png ├── editer-runcode.png ├── sublime-01.png └── sublime-02.png ├── docs ├── c_arrays.md ├── c_break_continue.md ├── c_comments.md ├── c_conditions.md ├── c_constants.md ├── c_data_types.md ├── c_enum.md ├── c_file_io.md ├── c_for_loop.md ├── c_functions.md ├── c_functions_decl.md ├── c_functions_parameters.md ├── c_functions_recursion.md ├── c_getstarted.md ├── c_keywords.md ├── c_math.md ├── c_memory_address.md ├── c_operators.md ├── c_output.md ├── c_pointers.md ├── c_preprocessors.md ├── c_strings.md ├── c_structs.md ├── c_switch.md ├── c_syntax.md ├── c_user_input.md ├── c_variables.md └── c_while_loop.md ├── example ├── calculations_with_cookies.c ├── division_with_float_values.c ├── hello.c ├── simple_calculations.c ├── using_a_variable.c └── using_more_variables.c ├── idoc.chapters.yml ├── idoc.yml ├── logo.svg ├── package.json └── renovate.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jaywcjlove 2 | buy_me_a_coffee: jaywcjlove 3 | custom: ["https://www.paypal.me/kennyiseeyou", "https://jaywcjlove.github.io/#/sponsor"] 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 20 15 | registry-url: 'https://registry.npmjs.org' 16 | 17 | - run: npm install 18 | - run: npm run build 19 | 20 | - name: Generate Contributors Images 21 | uses: jaywcjlove/github-action-contributors@main 22 | with: 23 | filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\]) 24 | output: dist/CONTRIBUTORS.svg 25 | avatarSize: 42 26 | 27 | - name: Create Tag 28 | id: create_tag 29 | uses: jaywcjlove/create-tag-action@main 30 | with: 31 | package-path: ./package.json 32 | 33 | - name: get tag version 34 | id: tag_version 35 | uses: jaywcjlove/changelog-generator@main 36 | 37 | - name: Deploy Website 38 | uses: peaceiris/actions-gh-pages@v4 39 | with: 40 | user_name: 'github-actions[bot]' 41 | user_email: 'github-actions[bot]@users.noreply.github.com' 42 | # commit_message: ${{ github.event.head_commit.message }} 43 | commit_message: ${{steps.tag_version.outputs.tag}} ${{ github.event.head_commit.message }} 44 | github_token: ${{ secrets.GITHUB_TOKEN }} 45 | publish_dir: ./dist 46 | 47 | - name: Generate Changelog 48 | id: changelog 49 | uses: jaywcjlove/changelog-generator@main 50 | with: 51 | token: ${{ secrets.GITHUB_TOKEN }} 52 | filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot) 53 | filter: (^[\s]+?[R|r]elease)|(^[R|r]elease) 54 | 55 | - name: Create Release 56 | uses: ncipollo/release-action@v1 57 | if: steps.create_tag.outputs.successful 58 | with: 59 | allowUpdates: true 60 | token: ${{ secrets.GITHUB_TOKEN }} 61 | name: ${{ steps.create_tag.outputs.version }} 62 | tag: ${{ steps.create_tag.outputs.version }} 63 | body: | 64 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) 65 | 66 | Documentation ${{ steps.changelog.outputs.tag }}: https://raw.githack.com/jaywcjlove/html-tutorial/${{ steps.changelog.outputs.gh-pages-short-hash }}/index.html 67 | Comparing Changes: ${{ steps.changelog.outputs.compareurl }} 68 | 69 | ${{ steps.changelog.outputs.changelog }} 70 | 71 | 72 | ## Docker 73 | 74 | [![Docker Image Version (latest by date)](https://img.shields.io/docker/v/wcjiang/c-tutorial?logo=docker)](https://hub.docker.com/r/wcjiang/c-tutorial) 75 | 76 | ```bash 77 | docker pull wcjiang/c-tutorial:${{steps.changelog.outputs.version}} 78 | ``` 79 | 80 | ```bash 81 | docker run --name c-tutorial --rm -d -p 9883:3000 wcjiang/c-tutorial:${{steps.changelog.outputs.version}} 82 | # Or 83 | docker run --name c-tutorial -itd -p 9883:3000 wcjiang/c-tutorial:${{steps.changelog.outputs.version}} 84 | ``` 85 | 86 | Visit the following URL in your browser 87 | 88 | ```bash 89 | http://localhost:9883/ 90 | ``` 91 | 92 | 93 | # Create Docker Image 94 | - name: Docker login 95 | if: steps.create_tag.outputs.successful 96 | run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }} 97 | 98 | - name: Build image 99 | if: steps.create_tag.outputs.successful 100 | run: docker image build -t c-tutorial . 101 | 102 | - name: Tags & Push image 103 | if: steps.create_tag.outputs.successful 104 | run: | 105 | echo "outputs.tag - ${{ steps.changelog.outputs.version }}" 106 | docker tag c-tutorial ${{ secrets.DOCKER_USER }}/c-tutorial:${{steps.changelog.outputs.version}} 107 | docker tag c-tutorial ${{ secrets.DOCKER_USER }}/c-tutorial:latest 108 | docker push ${{ secrets.DOCKER_USER }}/c-tutorial:${{steps.changelog.outputs.version}} 109 | docker push ${{ secrets.DOCKER_USER }}/c-tutorial:latest 110 | 111 | # # Create Docker Image in GitHub 112 | # - name: Login to GitHub registry 113 | # run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin 114 | 115 | # - name: Build docker image 116 | # run: docker build -t ghcr.io/jaywcjlove/c-tutorial:latest . 117 | 118 | # - name: Publish to GitHub registry 119 | # run: docker push ghcr.io/jaywcjlove/c-tutorial:latest 120 | 121 | # - name: Tag docker image (beta) and publish to GitHub registry 122 | # if: steps.create_tag.outputs.successful 123 | # run: | 124 | # echo "version: v${{ steps.changelog.outputs.version }}" 125 | # docker tag ghcr.io/jaywcjlove/c-tutorial:latest ghcr.io/jaywcjlove/c-tutorial:${{steps.changelog.outputs.version}} 126 | # docker push ghcr.io/jaywcjlove/c-tutorial:${{steps.changelog.outputs.version}} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | package-lock.json 4 | 5 | # Prerequisites 6 | *.d 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Linker output 15 | *.ilk 16 | *.map 17 | *.exp 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | 29 | # Shared objects (inc. Windows DLLs) 30 | *.dll 31 | *.so 32 | *.so.* 33 | *.dylib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | *.i*86 40 | *.x86_64 41 | *.hex 42 | 43 | # Debug files 44 | *.dSYM/ 45 | *.su 46 | *.idb 47 | *.pdb 48 | 49 | # Kernel Module Compile Results 50 | *.mod* 51 | *.cmd 52 | .tmp_versions/ 53 | modules.order 54 | Module.symvers 55 | Mkfile.old 56 | dkms.conf 57 | 58 | *.DS_Store 59 | *.bak 60 | *.tem 61 | *.temp 62 | #.swp 63 | *.*~ 64 | ~*.* 65 | 66 | # IDEA 67 | *.iml 68 | *.ipr 69 | *.iws 70 | .idea/ -------------------------------------------------------------------------------- /.idoc/.filesStat.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs/c_arrays.md": { 3 | "atime": "2022-05-03T17:18:57.540Z", 4 | "mtime": "2022-05-03T17:18:54.945Z", 5 | "ctime": "2022-05-03T17:18:54.945Z", 6 | "birthtime": "2022-05-01T15:32:10.058Z" 7 | }, 8 | "docs/c_break_continue.md": { 9 | "atime": "2022-05-02T09:25:51.289Z", 10 | "mtime": "2022-05-02T09:24:42.928Z", 11 | "ctime": "2022-05-02T09:24:42.928Z", 12 | "birthtime": "2022-05-01T15:32:10.058Z" 13 | }, 14 | "docs/c_comments.md": { 15 | "atime": "2022-05-01T17:54:41.852Z", 16 | "mtime": "2022-05-01T17:54:38.244Z", 17 | "ctime": "2022-05-01T17:54:38.244Z", 18 | "birthtime": "2022-05-01T15:32:10.057Z" 19 | }, 20 | "docs/c_conditions.md": { 21 | "atime": "2022-05-03T17:18:57.537Z", 22 | "mtime": "2022-05-03T17:18:54.945Z", 23 | "ctime": "2022-05-03T17:18:54.945Z", 24 | "birthtime": "2022-05-01T15:32:10.058Z" 25 | }, 26 | "docs/c_constants.md": { 27 | "atime": "2022-05-02T06:08:01.020Z", 28 | "mtime": "2022-05-02T06:07:58.921Z", 29 | "ctime": "2022-05-02T06:07:58.921Z", 30 | "birthtime": "2022-05-01T15:32:10.058Z" 31 | }, 32 | "docs/c_data_types.md": { 33 | "atime": "2022-05-03T17:18:56.835Z", 34 | "mtime": "2022-05-03T17:18:54.945Z", 35 | "ctime": "2022-05-03T17:18:54.945Z", 36 | "birthtime": "2022-05-01T15:32:10.058Z" 37 | }, 38 | "docs/c_enum.md": { 39 | "atime": "2022-05-02T13:22:52.003Z", 40 | "mtime": "2022-05-02T13:22:50.624Z", 41 | "ctime": "2022-05-02T13:22:50.624Z", 42 | "birthtime": "2022-05-02T13:09:04.512Z" 43 | }, 44 | "docs/c_for_loop.md": { 45 | "atime": "2022-05-03T17:18:56.830Z", 46 | "mtime": "2022-05-03T17:18:54.939Z", 47 | "ctime": "2022-05-03T17:18:54.939Z", 48 | "birthtime": "2022-05-01T15:32:10.058Z" 49 | }, 50 | "docs/c_functions.md": { 51 | "atime": "2022-05-02T10:46:21.629Z", 52 | "mtime": "2022-05-02T09:56:10.393Z", 53 | "ctime": "2022-05-02T09:56:10.393Z", 54 | "birthtime": "2022-05-01T15:32:10.059Z" 55 | }, 56 | "docs/c_functions_decl.md": { 57 | "atime": "2022-05-03T17:18:55.330Z", 58 | "mtime": "2022-05-03T17:18:54.939Z", 59 | "ctime": "2022-05-03T17:18:54.939Z", 60 | "birthtime": "2022-05-01T15:32:10.059Z" 61 | }, 62 | "docs/c_functions_parameters.md": { 63 | "atime": "2022-07-11T05:14:17.290Z", 64 | "mtime": "2022-07-11T05:14:17.258Z", 65 | "ctime": "2022-07-11T05:14:17.258Z", 66 | "birthtime": "2022-05-01T15:32:10.059Z" 67 | }, 68 | "docs/c_file_io.md": { 69 | "atime": "2022-05-04T17:18:24.637Z", 70 | "mtime": "2022-05-04T17:18:07.275Z", 71 | "ctime": "2022-05-04T17:18:07.275Z", 72 | "birthtime": "2022-05-04T16:26:43.500Z" 73 | }, 74 | "docs/c_math.md": { 75 | "atime": "2022-05-02T10:47:31.263Z", 76 | "mtime": "2022-05-02T10:46:19.577Z", 77 | "ctime": "2022-05-02T10:46:19.577Z", 78 | "birthtime": "2022-05-01T15:32:10.059Z" 79 | }, 80 | "docs/c_getstarted.md": { 81 | "atime": "2022-05-01T17:02:02.414Z", 82 | "mtime": "2022-05-01T17:02:01.071Z", 83 | "ctime": "2022-05-01T17:02:01.071Z", 84 | "birthtime": "2022-05-01T15:32:10.057Z" 85 | }, 86 | "docs/c_functions_recursion.md": { 87 | "atime": "2022-05-03T17:18:55.376Z", 88 | "mtime": "2022-05-03T17:18:54.939Z", 89 | "ctime": "2022-05-03T17:18:54.939Z", 90 | "birthtime": "2022-05-01T15:32:10.059Z" 91 | }, 92 | "docs/c_memory_address.md": { 93 | "atime": "2022-05-02T03:27:30.415Z", 94 | "mtime": "2022-05-02T03:26:34.231Z", 95 | "ctime": "2022-05-02T03:26:34.231Z", 96 | "birthtime": "2022-05-01T15:32:10.059Z" 97 | }, 98 | "docs/c_operators.md": { 99 | "atime": "2022-10-12T16:15:42.747Z", 100 | "mtime": "2022-10-12T16:15:42.714Z", 101 | "ctime": "2022-10-12T16:15:42.714Z", 102 | "birthtime": "2022-05-01T15:32:10.058Z" 103 | }, 104 | "docs/c_output.md": { 105 | "atime": "2022-05-02T07:11:16.780Z", 106 | "mtime": "2022-05-02T07:10:57.336Z", 107 | "ctime": "2022-05-02T07:10:57.336Z", 108 | "birthtime": "2022-05-01T15:32:10.057Z" 109 | }, 110 | "docs/c_pointers.md": { 111 | "atime": "2022-05-02T03:20:27.227Z", 112 | "mtime": "2022-05-02T03:19:44.753Z", 113 | "ctime": "2022-05-02T03:19:44.753Z", 114 | "birthtime": "2022-05-01T15:32:10.059Z" 115 | }, 116 | "docs/c_keywords.md": { 117 | "atime": "2022-05-04T16:35:48.205Z", 118 | "mtime": "2022-05-04T16:24:35.078Z", 119 | "ctime": "2022-05-04T16:24:35.078Z", 120 | "birthtime": "2022-05-02T13:26:33.983Z" 121 | }, 122 | "docs/c_preprocessors.md": { 123 | "atime": "2022-05-02T15:53:58.919Z", 124 | "mtime": "2022-05-02T15:53:57.542Z", 125 | "ctime": "2022-05-02T15:53:57.542Z", 126 | "birthtime": "2022-05-02T15:30:31.580Z" 127 | }, 128 | "docs/c_structs.md": { 129 | "atime": "2022-05-02T15:28:29.447Z", 130 | "mtime": "2022-05-02T15:28:28.053Z", 131 | "ctime": "2022-05-02T15:28:28.053Z", 132 | "birthtime": "2022-05-01T15:32:10.059Z" 133 | }, 134 | "docs/c_switch.md": { 135 | "atime": "2022-05-02T08:43:16.873Z", 136 | "mtime": "2022-05-02T08:43:10.698Z", 137 | "ctime": "2022-05-02T08:43:10.698Z", 138 | "birthtime": "2022-05-01T15:32:10.058Z" 139 | }, 140 | "docs/c_syntax.md": { 141 | "atime": "2022-05-01T17:55:16.431Z", 142 | "mtime": "2022-05-01T17:55:13.866Z", 143 | "ctime": "2022-05-01T17:55:13.866Z", 144 | "birthtime": "2022-05-01T15:32:10.057Z" 145 | }, 146 | "docs/c_user_input.md": { 147 | "atime": "2022-05-01T17:50:48.724Z", 148 | "mtime": "2022-05-01T17:50:46.958Z", 149 | "ctime": "2022-05-01T17:50:46.958Z", 150 | "birthtime": "2022-05-01T15:32:10.058Z" 151 | }, 152 | "docs/c_strings.md": { 153 | "atime": "2022-05-03T17:18:55.370Z", 154 | "mtime": "2022-05-03T17:18:54.939Z", 155 | "ctime": "2022-05-03T17:18:54.939Z", 156 | "birthtime": "2022-05-01T15:32:10.058Z" 157 | }, 158 | "docs/c_variables.md": { 159 | "atime": "2022-05-03T17:18:55.325Z", 160 | "mtime": "2022-05-03T17:18:54.939Z", 161 | "ctime": "2022-05-03T17:18:54.939Z", 162 | "birthtime": "2022-05-01T15:32:10.058Z" 163 | }, 164 | "docs/c_while_loop.md": { 165 | "atime": "2022-05-03T17:18:55.264Z", 166 | "mtime": "2022-05-03T17:18:54.897Z", 167 | "ctime": "2022-05-03T17:18:54.897Z", 168 | "birthtime": "2022-05-01T15:32:10.058Z" 169 | } 170 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # https://lipanski.com/posts/smallest-docker-image-static-website 2 | # https://github.com/lipanski/docker-static-website 3 | FROM lipanski/docker-static-website:latest 4 | 5 | # Copy the static website 6 | # Use the .dockerignore file to control what ends up inside the image! 7 | COPY ./dist . -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Kenny Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C Tutorial 2 | === 3 | 4 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) 5 | [![CI](https://github.com/jaywcjlove/c-tutorial/actions/workflows/ci.yml/badge.svg)](https://github.com/jaywcjlove/c-tutorial/actions/workflows/ci.yml) 6 | [![Docker Image Version (latest by date)](https://img.shields.io/docker/v/wcjiang/c-tutorial?logo=docker)](https://hub.docker.com/r/wcjiang/c-tutorial) 7 | 8 | C 语言是一种功能强大、简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定任务。 9 | 10 | ## 什么是 C? 11 | 12 | C 是 Dennis Ritchie (丹尼斯·里奇) 和 Brian Kernighan (布莱恩·柯林汉) 于 1972 年在贝尔实验室创建的通用编程语言,Dennis Ritchie 被称为 C 语言的创始人。 13 | 14 | 这是一种非常流行的语言,尽管它很古老。 15 | 16 | C 与 UNIX 密切相关,因为最初,C 语言被开发用于 UNIX 操作系统。它继承了以前语言如 B 和 BCPL 的许多特性。 17 | 18 | 让我们看看在 C 语言之前开发的编程语言。 19 | 20 | Language | Year | Developed By 21 | ---- | ---- | ---- 22 | Algol | 1960 | International Group 23 | BCPL | 1967 | Martin Richard 24 | B | 1970 | Ken Thompson 25 | Traditional C | 1972 | Dennis Ritchie 26 | K & R C | 1978 | Kernighan & Dennis Ritchie 27 | ANSI C | 1989 | ANSI Committee 28 | ANSI/ISO C | 1990 | ISO Committee 29 | C99 | 1999 | Standardization Committee 30 | 31 | 32 | ## 为什么要学习 C? 33 | 34 | - 它是世界上最流行的编程语言之一 35 | - 如果你懂 C,那么你学习其他流行的编程语言,如 Java、Python、C++、C# 等也没有问题,因为语法相似 36 | - 与其他编程语言(如 Java 和 Python)相比,C 非常快 37 | - C是非常通用的; 它可以用于应用程序和技术 38 | 39 | ## C 和 C++ 之间的区别 40 | 41 | C++ 是作为 C 的扩展开发的,两种语言的语法几乎相同 42 | C 和 C++ 的主要区别在于 C++ 支持类和对象,而 C 不支持 43 | 44 | 45 | 46 | ## 学习目录 47 | 48 | - [C 开始 Get Started](docs/c_getstarted.md) 49 | - [C 语法 Syntax](docs/c_syntax.md) 50 | - [C 输出(打印文本)Output](docs/c_output.md) 51 | - [C 注释 Comments](docs/c_comments.md) 52 | - [C 变量 Variables](docs/c_variables.md) 53 | - [C 数据类型 Data Types](docs/c_data_types.md) 54 | - [C 常量 Constants](docs/c_constants.md) 55 | - [C 运算符 Operators](docs/c_operators.md) 56 | - [C If...Else](docs/c_conditions.md) 57 | - [C Switch](docs/c_switch.md) 58 | - [C While 循环](docs/c_while_loop.md) 59 | - [C For 循环](docs/c_for_loop.md) 60 | - [C 跳出循环 Break/Continue](docs/c_break_continue.md) 61 | - [C 数组 Arrays](docs/c_arrays.md) 62 | - [C 枚举 Enum](docs/c_enum.md) 63 | - [C 字符串 Strings](docs/c_strings.md) 64 | - [C 用户输入 User Input](docs/c_user_input.md) 65 | - [C 内存地址 Memory Address](docs/c_memory_address.md) 66 | - [C 指针 Pointers](docs/c_pointers.md) 67 | - [C 预处理器](docs/c_preprocessors.md) 68 | - [C 函数 Functions](docs/c_functions.md) 69 | - [C 函数参数](docs/c_functions_parameters.md) 70 | - [C 函数声明](docs/c_functions_decl.md) 71 | - [C 递归](docs/c_functions_recursion.md) 72 | - [C 数学函数](docs/c_math.md) 73 | - [C 结构](docs/c_structs.md) 74 | - [C 中文件处理](docs/c_file_io.md) 75 | - [C 关键字 Keywords](docs/c_keywords.md) 76 | 77 | 78 | 79 | ## Contributors 80 | 81 | As always, thanks to our amazing contributors! 82 | 83 | 84 | 85 | 86 | 87 | Made with [action-contributors](https://github.com/jaywcjlove/github-action-contributors). 88 | 89 | ## License 90 | 91 | Licensed under the MIT License. 92 | -------------------------------------------------------------------------------- /assets/editer-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/c-tutorial/HEAD/assets/editer-01.png -------------------------------------------------------------------------------- /assets/editer-runcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/c-tutorial/HEAD/assets/editer-runcode.png -------------------------------------------------------------------------------- /assets/sublime-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/c-tutorial/HEAD/assets/sublime-01.png -------------------------------------------------------------------------------- /assets/sublime-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/c-tutorial/HEAD/assets/sublime-02.png -------------------------------------------------------------------------------- /docs/c_arrays.md: -------------------------------------------------------------------------------- 1 | C 数组 Arrays 2 | === 3 | 4 | 数组用于在单个变量中存储多个值,而不是为每个值声明单独的变量。 5 | 6 | 要创建一个数组,请定义数据类型(如`int`)并指定数组的名称,后跟**方括号`[]`**。 7 | 8 | 要向其中插入值,请在花括号 `{}` 内使用逗号 `,` 分隔的列表: 9 | 10 | ```c 11 | int myNumbers[] = {25, 50, 75, 100}; 12 | ``` 13 | 14 | 我们现在创建了一个包含四个整数的数组的变量。 15 | 16 | ## 访问数组的元素 17 | 18 | 要访问数组元素,请参考其**索引号**。 19 | 20 | 数组索引以 **0** 开头:`[0]` 是第一个元素。`[1]` 是第二个元素,依此类推。 21 | 22 | 此语句访问 `myNumbers` 中的**第一个元素 [0]** 的值: 23 | 24 | ```c 25 | int myNumbers[] = {25, 50, 75, 100}; 26 | printf("%d", myNumbers[0]); 27 | 28 | // 输出 25 29 | ``` 30 | 31 | ## 更改数组元素 32 | 33 | 要更改特定元素的值,请参阅索引号: 34 | 35 | ```c 36 | myNumbers[0] = 33; 37 | ``` 38 | 39 | ```c 40 | int myNumbers[] = {25, 50, 75, 100}; 41 | myNumbers[0] = 33; 42 | 43 | printf("%d", myNumbers[0]); 44 | 45 | // 现在输出 33 而不是 25 46 | ``` 47 | 48 | ## 循环遍历数组 49 | 50 | 您可以使用 [`for`](./c_for_loop.md) 循环遍历数组元素。 51 | 52 | 以下示例输出 `myNumbers` 数组中的所有元素: 53 | 54 | ```c 55 | int myNumbers[] = {25, 50, 75, 100}; 56 | int i; 57 | 58 | for (i = 0; i < 4; i++) { 59 | printf("%d\n", myNumbers[i]); 60 | } 61 | ``` 62 | 63 | ## 设置数组大小 64 | 65 | 另一种创建数组的常用方法是指定数组的大小,然后再添加元素: 66 | 67 | ```c 68 | // 声明一个由四个整数组成的数组: 69 | int myNumbers[4]; 70 | 71 | // 添加元素 72 | myNumbers[0] = 25; 73 | myNumbers[1] = 50; 74 | myNumbers[2] = 75; 75 | myNumbers[3] = 100; 76 | ``` 77 | 78 | 使用这种方法,**你必须知道数组的大小,**才能让程序存储足够的内存。 79 | 80 | 您无法在创建后更改数组的大小。 81 | -------------------------------------------------------------------------------- /docs/c_break_continue.md: -------------------------------------------------------------------------------- 1 | C 跳出循环 Break/Continue 2 | === 3 | 4 | ## Break 5 | 6 | 您已经看过本教程前面章节中使用的 `break` 语句。 它用于“跳出” [`switch`](./c_switch.md) 语句。 7 | 8 | `break` 语句也可用于跳出**循环**。 9 | 10 | 这个例子在 `i` 等于 4 时跳出循环: 11 | 12 | 13 | ```c 14 | int i; 15 | 16 | for (i = 0; i < 10; i++) { 17 | if (i == 4) { 18 | break; 19 | } 20 | printf("%d\n", i); 21 | } 22 | ``` 23 | 24 | ## Continue 25 | 26 | 如果指定条件发生,`continue` 语句会中断一次迭代(在循环中),并继续循环中的下一次迭代。 27 | 28 | 此示例跳过 4 的值: 29 | 30 | ```c 31 | int i; 32 | 33 | for (i = 0; i < 10; i++) { 34 | if (i == 4) { 35 | continue; 36 | } 37 | printf("%d\n", i); 38 | } 39 | ``` 40 | 41 | ## 在 While 循环中中断并继续 42 | 43 | 您还可以在 `while` 循环中使用 `break` 和 `continue`: 44 | 45 | ### Break 示例 46 | 47 | ```c 48 | int i = 0; 49 | 50 | while (i < 10) { 51 | if (i == 4) { 52 | break; 53 | } 54 | printf("%d\n", i); 55 | i++; 56 | } 57 | ``` 58 | 59 | ### Continue 示例 60 | 61 | ```c 62 | int i = 0; 63 | 64 | while (i < 10) { 65 | i++; 66 | if (i == 4) { 67 | continue; 68 | } 69 | printf("%d\n", i); 70 | } 71 | ``` 72 | 73 | 74 | ## break 示例 75 | 76 | ```c 77 | #include 78 | int main(){ 79 | int i=1, sum=0; 80 | while(1){ // 循环条件为死循环 81 | sum+=i; 82 | i++; 83 | if(i>100) break; 84 | } 85 | printf("%d\n", sum); 86 | return 0; 87 | } 88 | // 运行结果:5050 89 | ``` 90 | 91 | `while` 循环条件为 `1`,是一个死循环。当执行到第 `100` 次循环的时候,计算完 `i++;` 后 `i` 的值为 `101`,此时 `if` 语句的条件 `i> 100` 成立,执行 `break;` 语句,结束循环 92 | 93 | ```c 94 | #include 95 | int main(){ 96 | int i=1, j; 97 | while(1){ // 外层循环 98 | j=1; 99 | while(1){ // 内层循环 100 | printf("%-4d", i*j); 101 | j++; 102 | if(j>4) break; // 跳出内层循环 103 | } 104 | printf("\n"); 105 | i++; 106 | if(i>4) break; // 跳出外层循环 107 | } 108 | return 0; 109 | } 110 | // 运行结果: 111 | // 1 2 3 4 112 | // 2 4 6 8 113 | // 3 6 9 12 114 | // 4 8 12 16 115 | ``` 116 | 117 | 当 `j>4` 成立时,执行 `break;`,跳出内层循环;外层循环依然执行,直到 `i>4` 成立,跳出外层循环。内层循环共执行了 `4` 次,外层循环共执行了 `1` 次。 118 | 119 | ## continue 示例 120 | 121 | 语句的作用是跳过循环体中剩余的语句而强制进入下一次循环。`continue` 语句只用在 `while`、[`for`](c_for_loop.md) 循环中,常与 [`if`](./c_conditions.md) 条件语句一起使用,判断条件是否成立。 122 | 123 | ```c 124 | #include 125 | int main(){ 126 | char c = 0; 127 | while(c!='\n'){ // 回车键结束循环 128 | c=getchar(); 129 | if(c=='4' || c=='5'){ // 按下的是数字键 4 或 5 130 | continue; // 跳过当次循环,进入下次循环 131 | } 132 | putchar(c); 133 | } 134 | return 0; 135 | } 136 | // 运行结果: 137 | // 0123456789↙ 138 | // 01236789 139 | ``` 140 | 141 | 程序遇到 `while` 时,变量 `c` 的值为 `'\0'`,循环条件 `c!='\n'` 成立,开始第一次循环。`getchar()` 使程序暂停执行,等待用户输入,直到用户按下回车键才开始读取字符。 142 | 143 | 本例我们输入的是 `0123456789`,当读取到 `4` 或 `5` 时,`if` 的条件 `c=='4'||c=='5'`成立,就执行 `continue` 语句,结束当前循环,直接进入下一次循环,也就是说 `putchar(c);` 不会被执行到。而读取到其他数字时,`if` 的条件不成立,`continue` 语句不会被执行到,`putchar(c);` 就会输出读取到的字符。 144 | 145 | `break` 与 `continue` 的对比:`break` 用来结束所有循环,循环语句不再有执行的机会;`continue` 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。 146 | -------------------------------------------------------------------------------- /docs/c_comments.md: -------------------------------------------------------------------------------- 1 | C 注释 Comments 2 | === 3 | 4 | 注释可用于解释代码,并使其更具可读性。它还可用于在测试替代代码时阻止执行。 5 | 6 | 注释可以是单行或多行的。 7 | 8 | ## 单行注释 9 | 10 | 单行注释以两个正斜杠 (`//`) 开头。 11 | 12 | `//` 和行尾之间的任何文本都会被编译器忽略(不会被执行)。 13 | 14 | 此示例在一行代码之前使用单行注释: 15 | 16 | ```c 17 | // 这是一个注释 18 | printf("Hello World!"); 19 | ``` 20 | 21 | 此示例在代码行末尾使用单行注释: 22 | 23 | ```c 24 | printf("Hello World!"); // 这是一个注释 25 | ``` 26 | 27 | ## 多行注释 28 | 29 | 多行注释以 `/*` 开头,以 `*/` 结尾。 30 | 31 | `/*` 和 `*/` 之间的任何文本都将被编译器忽略: 32 | 33 | 34 | ```c 35 | /* 下面的代码将打印出 Hello World! 36 | 到屏幕上,真是太棒了 */ 37 | printf("Hello World!"); 38 | ``` 39 | 40 | ## 单行注释还是多行注释? 41 | 42 | 您要使用哪个取决于您。 通常,我们使用 `//` 表示简短的注释,使用 `/*` `*/` 表示较长的注释。 43 | 44 | 很高兴知道:在 C99 版本(1999 年发布)之前,您只能在 `C` 中使用多行注释。 -------------------------------------------------------------------------------- /docs/c_conditions.md: -------------------------------------------------------------------------------- 1 | C If ... Else 2 | === 3 | 4 | ## 条件和 If 语句 5 | 6 | 您从 [运算符章节](./c_operators.md) 中了解到,C 支持数学中的常见逻辑条件: 7 | 8 | * 小于:a < b 9 | * 小于或等于:a <= b 10 | * 大于:a > b 11 | * 大于等于:a >= b 12 | * 等于 a == b 13 | * 不等于:a != b 14 | 15 | 您可以使用这些条件为不同的决策执行不同的操作。 16 | 17 | C 有以下条件语句: 18 | 19 | * 使用 `if` 指定要执行的代码块,如果指定条件为真 20 | * 使用`else`指定要执行的代码块,如果相同的条件为假 21 | * 如果第一个条件为假,则使用 `else if` 指定要测试的新条件 22 | * 使用 `switch` 指定要执行的许多替代代码块 23 | 24 | ## if 语句 25 | 26 | 使用 `if` 语句指定在条件为 `true` 时要执行的 C 代码块。 27 | 28 | ### 语法 29 | 30 | ```c 31 | if (条件) { 32 | // 条件为真(true)时执行的代码块 33 | } 34 | ``` 35 | 36 | 其执行过程可表示为下图: 37 | 38 | ```bash 39 | ┆ 40 | ╭┈┈┈┈┈▼┈┈┈┈┈╮ 41 | ┆ condition ├┈┈┈╮ 42 | ╰┈┈┈┈┈┈┈┈┈┈┈╯ ┆ 43 | ┆ true ┆ false 44 | ▼ ┆ 45 | ╭┈┈┈┈┴┈┈┈┈╮ ┆ 46 | ┆ 语句块 ┆ ┆ 47 | ╰┈┈┈┈┬┈┈┈┈╯ ┆ 48 | ├┈◀┈┈┈┈┈┈┈╯ 49 | ▼ 50 | ``` 51 | 52 | 53 | 请注意,`if` 是小写字母。 大写字母(If 或 IF)会产生错误。 54 | 55 | 在下面的示例中,我们测试两个值来确定 20 是否大于 18。如果条件为 `true`,则打印一些文本: 56 | 57 | ```c 58 | if (20 > 18) { 59 | printf("20 大于 18"); 60 | } 61 | ``` 62 | 63 | 我们还可以测试变量: 64 | 65 | ```c 66 | int x = 20; 67 | int y = 18; 68 | if (x > y) { 69 | printf("x 大于 y"); 70 | } 71 | ``` 72 | 73 | **示例说明** 74 | 75 | 在上面的示例中,我们使用两个变量 **x** 和 **y** 来测试 x 是否大于 y(使用 `>` 运算符)。 由于 x 为 20,y 为 18,并且我们知道 20 大于 18,我们在屏幕上打印 “x 大于 y”。 76 | 77 | ## else 语句 78 | 79 | 使用 `else` 语句指定在条件(condition) 为 `false` 时要执行的代码块。 80 | 81 | ### 语法 82 | 83 | ```c 84 | if (条件) { 85 | // 条件为真(true)时执行的代码块 86 | } else { 87 | // 条件为假(false)时执行的代码块 88 | } 89 | ``` 90 | 91 | 其执行过程可表示为下图: 92 | 93 | ```bash 94 | ┆ 95 | ▼ 96 | true ╭┈┈┈┈┈┴┈┈┈┈┈╮ false 97 | ╭┈┈┈┈┈┈┈┤ condition ├┈┈┈┈┈┈┈╮ 98 | ▼ ╰┈┈┈┈┈┈┈┈┈┈┈╯ ▼ 99 | ╭┈┈┈┈┴┈┈┈┈┈╮ ╭┈┈┈┈┴┈┈┈┈┈╮ 100 | ┆ 语句块1 ┆ ┆ 语句块2 ┆ 101 | ╰┈┈┈┈┬┈┈┈┈┈╯ ╰┈┈┈┈┬┈┈┈┈┈╯ 102 | ╰┈┈┈┈┈┈┈┈┈┈┈┈┈┬┈┈┈┈┈┈┈┈┈┈┈┈┈╯ 103 | ▼ 104 | ``` 105 | 106 | ```c 107 | int time = 20; 108 | if (time < 18) { 109 | printf("再会!"); 110 | } else { 111 | printf("晚上好!"); 112 | } 113 | // 输出 -> "晚上好!" 114 | ``` 115 | 116 | **示例说明** 117 | 118 | 在上面的示例中,时间 (20) 大于 18,因此条件为 `false`。 因此,我们转到 `else` 条件并打印到屏幕“晚安”。 如果时间小于 18,程序将打印 “晚上好!”。 119 | 120 | ## else if 语句 121 | 122 | 如果第一个条件为 `false`,则使用 `else if` 语句指定新条件。 123 | 124 | ### 语法 125 | 126 | ```c 127 | if (条件1) { 128 | // 如果 条件 1 为真(true),则要执行的代码块 129 | } else if (条件2) { 130 | // 如果 条件 1 为假(false)且 条件 2 为真(true),则要执行的代码块 131 | } else { 132 | // 如果 条件 1 为假(false)且 条件 2 为假(false),则要执行的代码块 133 | } 134 | ``` 135 | 136 | ```c 137 | int time = 22; 138 | if (time < 10) { 139 | printf("早上好!"); 140 | } else if (time < 20) { 141 | printf("再会!"); 142 | } else { 143 | printf("晚上好!"); 144 | } 145 | // 输出 -> "晚上好!" 146 | ``` 147 | 148 | **示例说明** 149 | 150 | 在上面的示例中,时间 (22) 大于 10,因此**第一个条件**为 `false`。 `else if` 语句中的下一个条件也是 `false`,所以我们继续讨论 `else` 条件,因为 **条件1** 和 **条件2** 都是 `false` - 并打印到 屏幕“晚上好”。 151 | 152 | 但是,如果时间是 14,我们的程序将打印“再会!”。 153 | 154 | ## 另一个例子 155 | 156 | 这个例子展示了如何使用 `if..else if` 来判断一个数字是正数还是负数: 157 | 158 | ```c 159 | int myNum = 10; // Is this a positive or negative number? 160 | 161 | if (myNum > 0) 162 | printf("该值为正数。"); 163 | else if (myNum < 0) 164 | printf("该值为负数。"); 165 | else 166 | printf("值为 0。"); 167 | ``` 168 | 169 | ## 三元运算符 170 | 171 | 还有一个简写 `if else`,它被称为三元运算符,因为它由三个操作数组成。它可用于用单行替换多行代码。它通常用于替换简单的 `if else` 语句: 172 | 173 | ```c 174 | 变量 = (条件) ? 表达式真(true) : 表达式假(false); 175 | ``` 176 | 177 | 原始示例: 178 | 179 | ```c 180 | int time = 20; 181 | if (time < 18) { 182 | printf("再会!"); 183 | } else { 184 | printf("晚上好!"); 185 | } 186 | ``` 187 | 188 | 简化示例: 189 | 190 | ```c 191 | int time = 20; 192 | (time < 18) ? printf("再会!") : printf("晚上好!"); 193 | ``` 194 | 195 | 如果您想使用传统的 `if...else` 语句或三元运算符,这完全取决于您。 -------------------------------------------------------------------------------- /docs/c_constants.md: -------------------------------------------------------------------------------- 1 | C 常量 Constants 2 | === 3 | 4 | ## 常量 5 | 6 | 当您不希望其他人(或您自己)覆盖现有变量值时,请使用 `const` 关键字(这会将变量声明为`常量`,这意味着**不可更改且只读**): 7 | 8 | ```c 9 | const int myNum = 15; // myNum 将始终为 15 10 | myNum = 10; // error: assignment of read-only variable 'myNum' 11 | ``` 12 | 13 | 14 | 当您具有不太可能更改的值时,您应该始终将变量声明为常量: 15 | 16 | ```c 17 | const int minutesPerHour = 60; 18 | const float PI = 3.14; 19 | ``` 20 | 21 | ## 常量笔记 22 | 23 | 当你声明一个常量变量时,它必须被赋值: 24 | 25 | 像这样: 26 | 27 | ```c 28 | const int minutesPerHour = 60; 29 | ``` 30 | 31 | 然而,下面示例将不起作用报错: 32 | 33 | ```c 34 | const int minutesPerHour; 35 | minutesPerHour = 60; // error 36 | ``` 37 | 38 | 39 | ## 最佳实践 40 | 41 | 关于常量变量的另一件事是,用 `大写` 声明它们被认为是一种好习惯。 它不是必需的,但对代码可读性很有用,并且对于 C 程序员来说很常见: 42 | 43 | ```c 44 | const int BIRTHYEAR = 1980; 45 | ``` -------------------------------------------------------------------------------- /docs/c_data_types.md: -------------------------------------------------------------------------------- 1 | C 数据类型 Data Types 2 | === 3 | 4 | 5 | ## 数据类型 6 | 7 | 如[变量章节](c_variables.md)中所述,C 中的变量必须是指定的**数据类型**,并且必须在 [`printf()`](./c_output.md) 函数中使用**格式说明符**才能显示 它: 8 | 9 | ```c 10 | // 创建变量 11 | int myNum = 5; // 整数 12 | float myFloatNum = 5.99; // 浮点数 13 | char myLetter = 'D'; // 字符串 14 | 15 | // 打印输出变量 16 | printf("%d\n", myNum); 17 | printf("%f\n", myFloatNum); 18 | printf("%c\n", myLetter); 19 | ``` 20 | 21 | ## 基本数据类型 22 | 23 | 数据类型指定变量将存储的信息的大小和类型。 24 | 25 | 让我们看看基本的数据类型。它的大小是根据 32 位体系结构给出的: 26 | 27 | | 数据类型 | 大小 Size | 范围 Range | 描述 Description | 28 | | ----- | ----- | ----- | ----- | 29 | | `char` | 1 字节 | `−128` ~ `127` | 单个字符/字母/数字/ASCII | 30 | | signed char | 1 字节 | `−128` ~ `127` | - | 31 | | unsigned char | 1 字节 | `0` ~ `255` | - | 32 | | `int` | `2` 到 `4` 字节 | `−32,768` ~ `32,767` | 存储整数 | 33 | | signed int | 2 字节 | `−32,768` ~ `32,767` | | 34 | | unsigned int | 2 字节 | `0` ~ `65,535` | | 35 | | short int | 2 字节 | `−32,768` ~ `32,767` | | 36 | | signed short int | 2 字节 | `−32,768` ~ `32,767` | | 37 | | unsigned short int | 2 字节 | `0` ~ `65,535` | | 38 | | long int | 4 字节 | `-2,147,483,648` ~ `2,147,483,647` | | 39 | | signed long int | 4 字节 | `-2,147,483,648` ~ `2,147,483,647` | | 40 | | unsigned long int | 4 字节 | `0` ~ `4,294,967,295` | | 41 | | `float` | 4 字节 | | | 42 | | `double` | 8 字节 | | | 43 | | long double | 10 字节 | | | 44 | 45 | 说 明 | 字符型 | 短整型 | 整型 | 长整型 | 单精度浮点型 | 双精度浮点型 | 无类型 46 | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- 47 | 数据类型 | char | short | int | long | float | double | void 48 | 49 | ## 基本格式说明符 50 | 51 | 每种数据类型都有不同的格式说明符。 这里是其中的一些: 52 | 53 | | 格式说明符 | 数据类型 | 54 | | ----- | ----- | 55 | | `%d` 或 `%i` | `int` 整数 | 56 | | `%f` | `float` 单精度的十进制类型 | 57 | | `%lf` | `double` 高精度浮点数据或数字 | 58 | | `%c` | `char` 字符 | 59 | | `%s` | 用于 **[strings](c_strings.md)**,您可以在 [`strings`](c_strings.md) 中了解更多信息 | 60 | 61 | 62 | | | short | int | long | 63 | | ---- | ---- | ---- | ---- | 64 | | 8 进制 | `%ho` | `%o` | `%lo` | 65 | | 10 进制 | `%hd` | `%d` | `%ld` | 66 | | 16 进制 | `%hx` 或者 `%hX` | `%x` 或者 `%X` | `%lx` 或者 `%lX` | 67 | 68 | ### int 整数 69 | 70 | ```c 71 | // 创建 整数 变量 72 | int myNum = 5; 73 | // 打印输出变量 74 | printf("%d\n", myNum); 75 | ``` 76 | 77 | ### float 单精度的十进制类型 78 | 79 | ```c 80 | float myFloatNum = 5.99; // 浮点数 81 | // 打印输出变量 82 | printf("%f\n", myFloatNum); 83 | ``` 84 | 85 | ### char 字符 86 | 87 | ```c 88 | char myLetter = 'D'; // 字符串 89 | // 打印输出变量 90 | printf("%c\n", myLetter); 91 | ``` 92 | 93 | ### double 高精度浮点数据或数字 94 | 95 | 范围是 `1.7E-308` 到 `1.7E+308`。双精度数据可以用实数 (`1` 到 `10`)、小数 (`0.1` 到 `11.002`) 和负数 (-1 到 -0.00002) 表示。它可以容纳大约 15 到 16 位小数点前后的数字。 96 | 97 | ```c 98 | double myDouble = 3.2325467; 99 | // 打印输出变量 100 | printf("%lf\n", myDouble); 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/c_enum.md: -------------------------------------------------------------------------------- 1 | C 枚举 Enum 2 | === 3 | 4 | C 中的枚举也称为枚举类型。 它是一种用户定义的数据类型,由整数值组成,并为这些值提供有意义的名称。 在 C 中使用 `enum` 使程序易于理解和维护。 枚举是使用 enum 关键字定义的。 5 | 6 | 以下是在 C 中定义枚举的方式: 7 | 8 | ```c 9 | enum flag { integer_const1, integer_const2, .....integter_constN }; 10 | ``` 11 | 12 | `enum` 是一个新的关键字,专门用来定义枚举类型,这也是它在 C 语言中的唯一用途;`flag` 是枚举类型的名字;integer_const1, integer_const2, integer_const3, ...... 是每个值对应的名字的列表。注意最后的 `;` 不能少。 13 | 14 | 15 | ## 创建枚举类型 16 | 17 | 列出一个星期有几天 18 | 19 | ```c 20 | enum week { Mon, Tues, Wed, Thurs, Fri, Sat, Sun }; 21 | ``` 22 | 23 | 可以看到,我们仅仅给出了名字,却没有给出名字对应的值,这是因为枚举值默认从 `0` 开始,往后逐个加 `1`(递增);也就是说,`week` 中的 Mon、Tues ...... Sun 对应的值分别为 0、1 ... 6。 24 | 25 | 我们也可以给每个名字都指定一个值: 26 | 27 | ```c 28 | enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 }; 29 | ``` 30 | 31 | 上面示例可以简化一下,只给第一个名字指定值,这样枚举值就从 1 开始递增,跟上面的写法是等效的: 32 | 33 | ```c 34 | enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun }; 35 | ``` 36 | 37 | ## 定义枚举变量 38 | 39 | ```c 40 | enum week a, b, c; 41 | ``` 42 | 43 | 定义枚举类型的同时定义变量 44 | 45 | ```c 46 | enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c; 47 | ``` 48 | 49 | 有了枚举变量,就可以把列表中的值赋给它 50 | 51 | ```c 52 | enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun }; 53 | enum week a = Mon, b = Wed, c = Sat; 54 | 55 | // 或者 56 | 57 | enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat; 58 | ``` 59 | 60 | ## 示例 61 | 62 | 下面是一个简单的枚举示例应用,判断用户输入的是星期几: 63 | 64 | ```c 65 | #include 66 | int main(){ 67 | enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day; 68 | scanf("%d", &day); 69 | switch(day){ 70 | case Mon: puts("Monday"); break; 71 | case Tues: puts("Tuesday"); break; 72 | case Wed: puts("Wednesday"); break; 73 | case Thurs: puts("Thursday"); break; 74 | case Fri: puts("Friday"); break; 75 | case Sat: puts("Saturday"); break; 76 | case Sun: puts("Sunday"); break; 77 | default: puts("Error!"); 78 | } 79 | return 0; 80 | } 81 | ``` 82 | 83 | 1. 枚举列表中的 Mon、Tues、Wed 这些标识符的作用范围是全局的(严格来说是 main() 函数内部),不能再定义与它们名字相同的变量。 84 | 2. Mon、Tues、Wed 等都是常量,不能对它们赋值,只能将它们的值赋给其他的变量。 -------------------------------------------------------------------------------- /docs/c_file_io.md: -------------------------------------------------------------------------------- 1 | C 中文件处理 2 | === 3 | 4 | 在编程中,我们可能需要多次生成某些特定的输入数据。有时,仅在控制台上显示数据是不够的。要显示的数据可能非常大,在控制台上只能显示有限的数据,而且由于内存是容易丢失的,不可能一次又一次地恢复程序生成的数据。 但是,如果我们需要这样做,我们可以将其存储到本地文件系统中,该文件系统是易失的,并且每次都可以访问。 在这里,需要在 C 中处理文件。 5 | 6 | C 中的文件处理使我们能够通过我们的 C 程序创建、更新、读取和删除存储在本地文件系统中的文件。 可以对文件执行以下操作。 7 | 8 | - 创建新文件 9 | - 打开现有文件 10 | - 从文件中读取 11 | - 写入文件 12 | - 删除文件 13 | 14 | ## 文件处理函数 15 | 16 | C 库中有许多函数可以打开、读取、写入、搜索和关闭文件。 文件函数列表如下: 17 | 18 | 函数 | 描述 Description 19 | ---- | ---- 20 | fopen() | 打开新文件或现有文件 21 | fprintf() | 将数据写入文件 22 | fscanf() | 从文件中读取数据 23 | fputc() | 将一个字符写入文件 24 | fgetc() | 从文件中读取一个字符 25 | fclose() | 关闭文件 26 | fseek() | 将文件指针设置到给定位置 27 | fputw() | 将整数写入文件 28 | fgetw() | 从文件中读取一个整数 29 | ftell() | 返回当前位置 30 | rewind() | 将文件指针设置为文件的开头 31 | 32 | 33 | ## 打开文件:fopen() 34 | 35 | 我们必须先打开一个文件,然后它才能被读取、写入或更新。`fopen()` 函数用于打开文件。`fopen()` 的语法如下所示: 36 | 37 | ```c 38 | FILE *fopen( const char * filename, const char * mode ); 39 | ``` 40 | 41 | fopen() 函数接受两个参数: 42 | 43 | - 文件名(字符串)。 如果文件存储在某个特定位置,那么我们必须提及文件存储的路径。例如,文件名可以像“/some_folder/some_file.ext”。 44 | - 打开文件的模式。 它是一个字符串。 45 | 46 | 我们可以在 fopen() 函数中使用以下模式之一。 47 | 48 | 模式 Mode | 描述 Description 49 | ---- | ---- 50 | r | 以读取模式打开一个文本文件,允许读取文件。 51 | w | 以写模式打开一个文本文件,允许写入文件。 52 | a | 以追加模式打开一个文本文件,如果文件不存在,则会创建一个新文件。 53 | r+ | 以读写模式打开一个文本文件,允许读写文件。 54 | w+ | 以读写模式打开一个文本文件,允许读写文件。 55 | a+ | 以读写模式打开一个文本文件,允许读写文件。 56 | rb | 以读取模式打开二进制文件 57 | wb | 以写入模式打开二进制文件 58 | ab | 以追加模式打开二进制文件 59 | rb+ | 以读写模式打开二进制文件 60 | wb+ | 以读写模式打开二进制文件 61 | ab+ | 以读写模式打开二进制文件 62 | 63 | 64 | 65 | ```c 66 | #include 67 | void main( ) { 68 | FILE *fp; 69 | char ch; 70 | fp = fopen("file_handle.c", "r"); 71 | while (1) { 72 | ch = fgetc(fp); 73 | if (ch == EOF) 74 | break; 75 | printf("%c", ch); 76 | } 77 | fclose(fp); 78 | } 79 | ``` 80 | 81 | 输出,将打印文件的内容: 82 | 83 | ```bash 84 | #include 85 | void main( ) { 86 | FILE *fp; 87 | char ch; 88 | fp = fopen("file_handle.c", "r"); 89 | while (1) { 90 | ch = fgetc(fp); 91 | if (ch == EOF) 92 | break; 93 | printf("%c", ch); 94 | } 95 | fclose(fp); 96 | } 97 | ``` 98 | 99 | ## 关闭文件:fclose() 100 | 101 | `fclose()` 函数用于关闭文件。 对文件执行所有操作后,必须关闭该文件。`fclose()` 函数的语法如下: 102 | 103 | ```c 104 | int fclose(FILE *fp); 105 | ``` 106 | 107 | ## 写入文件:fprintf() 108 | 109 | `fprintf()` 函数用于将字符集写入文件。 它将格式化的输出发送到流。 110 | 111 | ```c 112 | int fprintf(FILE *stream, const char *format [, argument, ...]) 113 | ``` 114 | 115 | ```c 116 | #include 117 | main() { 118 | FILE *fp; 119 | fp = fopen("file.txt", "w"); // 打开文件 120 | fprintf(fp, "Hello file by fprintf...\n"); // 将数据写入文件 121 | fclose(fp); // 关闭文件 122 | } 123 | ``` 124 | 125 | ## 读取文件:fscanf() 126 | 127 | `fscanf()` 函数用于从文件中读取字符集。 它从文件中读取一个单词并在文件末尾返回 EOF。 128 | 129 | ```c 130 | int fscanf(FILE *stream, const char *format [, argument, ...]) 131 | ``` 132 | 133 | ```c 134 | #include 135 | main(){ 136 | FILE *fp; 137 | char buff[255]; // 创建 char 数组来存储文件数据 138 | fp = fopen("file.txt", "r"); 139 | while(fscanf(fp, "%s", buff)!=EOF) { 140 | printf("%s ", buff); 141 | } 142 | fclose(fp); 143 | } 144 | ``` 145 | 146 | ## C 文件示例:存储员工信息 147 | 148 | 让我们看一个文件处理示例,用于存储用户从控制台输入的员工信息。 我们将存储员工的 ID、姓名和薪水。 149 | 150 | ```c 151 | #include 152 | void main() { 153 | FILE *fptr; 154 | int id; 155 | char name[30]; 156 | float salary; 157 | fptr = fopen("emp.txt", "w+"); /* 打开文件 */ 158 | if (fptr == NULL) { 159 | printf("文件不存在 \n"); 160 | return; 161 | } 162 | printf("Enter the id\n"); 163 | scanf("%d", &id); 164 | fprintf(fptr, "Id= %d\n", id); 165 | printf("Enter the name \n"); 166 | scanf("%s", name); 167 | fprintf(fptr, "Name= %s\n", name); 168 | printf("Enter the salary\n"); 169 | scanf("%f", &salary); 170 | fprintf(fptr, "Salary= %.2f\n", salary); 171 | fclose(fptr); 172 | } 173 | ``` 174 | 175 | 输出 176 | 177 | ```bash 178 | Enter the id 179 | 1 180 | Enter the name 181 | kenny 182 | Enter the salary 183 | 120000 184 | ``` 185 | 186 | 现在从当前目录打开文件。你会看到 emp.txt 文件。它有以下信息: 187 | 188 | ```bash 189 | Id= 1 190 | Name= kenny 191 | Salary= 120000 192 | ``` 193 | 194 | ## 写入文件:fputc() 195 | 196 | `fputc()` 函数用于将单个字符写入文件。它将一个字符输出到一个字符串 197 | 198 | ```c 199 | int fputc(int c, FILE *stream) 200 | ``` 201 | 202 | ```c 203 | #include 204 | main(){ 205 | FILE *fp; 206 | fp = fopen("file1.txt", "w"); // 打开文件 207 | fputc('a',fp); // 将单个字符写入文件 208 | fclose(fp); // 关闭文件 209 | } 210 | ``` 211 | 212 | ## 读取文件:fgetc() 213 | 214 | `fgetc()` 函数从文件中返回单个字符。它从流中获取一个字符。它在文件末尾返回 EOF: 215 | 216 | ```c 217 | int fgetc(FILE *stream) 218 | ``` 219 | 220 | ```c 221 | #include 222 | #include 223 | void main() { 224 | FILE *fp; 225 | char c; 226 | clrscr(); 227 | fp=fopen("myfile.txt", "r"); 228 | while((c=fgetc(fp))!=EOF){ 229 | printf("%c", c); 230 | } 231 | fclose(fp); 232 | getch(); 233 | } 234 | ``` 235 | 236 | ## 写入文件:fputs() 237 | 238 | `fputs()` 函数将一行字符写入文件。它将字符串输出到流 239 | 240 | ```c 241 | int fputs(const char *s, FILE *stream) 242 | ``` 243 | 244 | ```c 245 | #include 246 | #include 247 | void main(){ 248 | FILE *fp; 249 | clrscr(); 250 | fp = fopen("myfile2.txt","w"); 251 | fputs("hello c programming",fp); 252 | fclose(fp); 253 | getch(); 254 | } 255 | ``` 256 | 257 | ## 读取文件:fgets() 258 | 259 | `fgets()` 函数从文件中读取一行字符。 它从流中获取字符串: 260 | 261 | ```c 262 | char* fgets(char *s, int n, FILE *stream) 263 | ``` 264 | 265 | ```c 266 | #include 267 | #include 268 | void main() { 269 | FILE *fp; 270 | char text[300]; 271 | clrscr(); 272 | 273 | fp=fopen("myfile2.txt", "r"); 274 | printf("%s", fgets(text, 200, fp)); 275 | fclose(fp); 276 | getch(); 277 | } 278 | ``` 279 | 280 | ## fseek() 281 | 282 | `fseek()` 函数用于将文件指针设置为指定的偏移量。 它用于将数据写入所需位置的文件: 283 | 284 | ```c 285 | int fseek(FILE *stream, long int offset, int whence) 286 | ``` 287 | 288 | `fseek()` 函数中使用了 3 个常量:`SEEK_SET`、`SEEK_CUR` 和 `SEEK_END`。 289 | 290 | ```c 291 | #include 292 | void main(){ 293 | FILE *fp; 294 | fp = fopen("myfile.txt","w+"); 295 | fputs("This is Book", fp); 296 | 297 | fseek(fp, 7, SEEK_SET); 298 | fputs("Kenny Wong", fp); 299 | fclose(fp); 300 | } 301 | ``` 302 | 303 | ## rewind() 304 | 305 | `rewind()` 函数将文件指针设置在流的开头。 如果您必须多次使用流,这很有用: 306 | 307 | ```c 308 | void rewind(FILE *stream) 309 | ``` 310 | 311 | ```c 312 | #include 313 | #include 314 | void main(){ 315 | FILE *fp; 316 | char c; 317 | clrscr(); 318 | fp=fopen("file.txt", "r"); 319 | while((c=fgetc(fp)) != EOF){ 320 | printf("%c", c); 321 | } 322 | rewind(fp); // 将文件指针移动到文件的开头 323 | while((c=fgetc(fp)) != EOF){ 324 | printf("%c", c); 325 | } 326 | fclose(fp); 327 | getch(); 328 | } 329 | // 输出 330 | // Hello World!Hello World! 331 | ``` 332 | 333 | 如您所见,`rewind()` 函数将文件指针移动到文件的开头,这就是 `Hello World!` 被打印 2 次的原因。 如果你不调用 `rewind()` 函数,“Hello World!” 将只打印一次。 334 | 335 | ## ftell() 336 | 337 | `ftell()` 函数返回指定流的当前文件位置。 我们可以使用 `ftell()` 函数在文件末尾移动文件指针后获取文件的总大小。 我们可以使用 `SEEK_END` 常量将文件指针移动到文件末尾。 338 | 339 | ```c 340 | long int ftell(FILE *stream) 341 | ``` 342 | 343 | ```c 344 | #include 345 | #include 346 | void main (){ 347 | FILE *fp; 348 | int length; 349 | clrscr(); 350 | fp = fopen("file.txt", "r"); 351 | fseek(fp, 0, SEEK_END); 352 | 353 | length = ftell(fp); 354 | 355 | fclose(fp); 356 | printf("Size of file: %d bytes", length); 357 | getch(); 358 | } 359 | // 输出 360 | // Size of file: 18 bytes 361 | ``` -------------------------------------------------------------------------------- /docs/c_for_loop.md: -------------------------------------------------------------------------------- 1 | C For 循环 2 | === 3 | 4 | ## For 循环 5 | 6 | 当您确切知道要循环一段代码的次数时,请使用 `for` 循环而不是 `while` 循环: 7 | 8 | ### 语法 9 | 10 | ```c 11 | for (表达式 1; 表达式 2; 表达式 3) { 12 | // 要执行的代码块 13 | } 14 | ``` 15 | 16 | `表达式 1` 在代码块执行之前执行(一次)。 17 | 18 | `表达式 2` 定义了执行代码块的条件。 19 | 20 | `表达式 3` 在代码块执行后(每次)执行。 21 | 22 | 下面的示例将打印数字 0 到 4: 23 | 24 | ### 示例 25 | 26 | ```c 27 | int i; 28 | 29 | for (i = 0; i < 5; i++) { 30 | printf("%d\n", i); 31 | } 32 | ``` 33 | 34 | **示例说明** 35 | 36 | `表达式 1`: 在循环开始之前设置一个变量(int i = 0)。 37 | 38 | `表达式 2`: 定义循环运行的条件(i 必须小于 5)。 如果条件为真,循环将重新开始,如果条件为假,循环将结束。 39 | 40 | `表达式 3`: 每次执行循环中的代码块时增加一个值 (i++)。 41 | 42 | ## 另一个例子 43 | 44 | 此示例将仅打印 0 到 10 之间的偶数值: 45 | 46 | 47 | ```c 48 | for (i = 0; i <= 10; i = i + 2) { 49 | printf("%d\n", i); 50 | } 51 | ``` -------------------------------------------------------------------------------- /docs/c_functions.md: -------------------------------------------------------------------------------- 1 | C 函数 Functions 2 | === 3 | 4 | 函数是一段代码,只有在被调用时才会运行。 5 | 6 | 您可以将数据(称为参数)传递给函数。 7 | 8 | 函数用于执行某些操作,它们对于重用代码很重要:定义代码一次,多次使用。 9 | 10 | ## 预定义函数 11 | 12 | 所以事实证明你已经知道函数是什么了。 在学习本教程的过程中,您一直在使用它! 13 | 14 | 比如 `main()` 是一个函数,用来执行代码,`printf()`是一个函数; 用于向屏幕输出/打印文本: 15 | 16 | ```c 17 | int main() { 18 | printf("Hello World!"); 19 | return 0; 20 | } 21 | ``` 22 | 23 | ## 创建函数 24 | 25 | 要创建(通常称为 *declare*)您自己的函数,请指定函数的名称,后跟括号 `()` 和大括号 `{}`: 26 | 27 | ### 语法 28 | 29 | ```c 30 | void myFunction() { 31 | // 要执行的代码 32 | } 33 | ``` 34 | 35 | **示例解释** 36 | 37 | * `myFunction()` 是函数的名称 38 | * `void` 表示函数没有返回值。 您将在下一章稍后了解有关返回值的更多信息 39 | * 在函数(主体)内部,添加定义函数应该做什么的代码 40 | 41 | ## 调用函数 42 | 43 | 声明的函数不会立即执行。 它们被“保存以备后用”,并在调用时执行。 44 | 45 | 要调用函数,请编写函数名,后跟两个括号 `()` 和一个分号 `;` 46 | 47 | 在以下示例中,`myFunction()` 用于在调用时打印文本(操作): 48 | 49 | 在 `main` 中,调用 `myFunction()`: 50 | 51 | ```c 52 | // 创建函数 53 | void myFunction() { 54 | printf("晚上好!"); 55 | } 56 | 57 | int main() { 58 | myFunction(); // 调用函数 59 | return 0; 60 | } 61 | // 输出 -> "晚上好!" 62 | ``` 63 | 64 | 一个函数可以被多次调用: 65 | 66 | ```c 67 | void myFunction() { 68 | printf("晚上好!"); 69 | } 70 | 71 | int main() { 72 | myFunction(); 73 | myFunction(); 74 | myFunction(); 75 | return 0; 76 | } 77 | 78 | // 晚上好! 79 | // 晚上好! 80 | // 晚上好! 81 | ``` -------------------------------------------------------------------------------- /docs/c_functions_decl.md: -------------------------------------------------------------------------------- 1 | C 函数声明和定义 2 | === 3 | 4 | 您刚刚从前面的章节中了解到,您可以通过以下方式创建和调用函数: 5 | 6 | ## 示例 1 7 | 8 | ```c 9 | // 创建函数 10 | void myFunction() { 11 | printf("晚上好!"); 12 | } 13 | 14 | int main() { 15 | myFunction(); // 调用函数 16 | return 0; 17 | } 18 | ``` 19 | 20 | 一个函数由两部分组成: 21 | 22 | - **Declaration声明:** 函数的名称、返回类型和参数(如果有) 23 | - **definition:** 函数体(要执行的代码) 24 | 25 | ```c 26 | void myFunction() { // 声明 declaration 27 | // 函数体(要执行的代码)(definition) 28 | } 29 | ``` 30 | 31 | 对于代码优化,建议将函数的声明和定义分开。 32 | 33 | 你会经常看到 C 程序在 `main()` 上方有函数声明,在 `main()` 下方有函数定义。 这将使代码更好地组织和更容易阅读: 34 | 35 | ## 示例 2 36 | 37 | ```c 38 | // 函数声明 39 | void myFunction(); 40 | 41 | // 主要方法 42 | int main() { 43 | myFunction(); // 调用函数 44 | return 0; 45 | } 46 | 47 | // 函数定义 48 | void myFunction() { 49 | printf("晚上好!"); 50 | } 51 | ``` 52 | 53 | ## 另一个例子 54 | 55 | 如果我们使用上一章中关于函数参数和返回值的示例: 56 | 57 | ```c 58 | int myFunction(int x, int y) { 59 | return x + y; 60 | } 61 | 62 | int main() { 63 | int result = myFunction(5, 3); 64 | printf("Result is = %d", result); 65 | 66 | return 0; 67 | } 68 | // 输出 8 (5 + 3) 69 | ``` 70 | 71 | 像这样编写它被认为是一种好习惯: 72 | 73 | ```c 74 | // 函数声明 75 | int myFunction(int, int); 76 | 77 | // 主要方法 78 | int main() { 79 | int result = myFunction(5, 3); // 调用函数 80 | printf("Result is = %d", result); 81 | 82 | return 0; 83 | } 84 | 85 | // 函数定义 86 | int myFunction(int x, int y) { 87 | return x + y; 88 | } 89 | ``` -------------------------------------------------------------------------------- /docs/c_functions_parameters.md: -------------------------------------------------------------------------------- 1 | C 函数参数 2 | === 3 | 4 | ## 参数 5 | 6 | 信息可以作为参数(Parameters/Arguments)传递给函数。 参数在函数内部充当变量。 7 | 8 | 参数在函数名之后的括号内指定。您可以添加任意数量的参数,只需用逗号分隔它们: 9 | 10 | ```c 11 | returnType functionName(parameter1, parameter2, parameter3) { 12 | // 要执行的代码 13 | } 14 | ``` 15 | 16 | 以下函数采用带有 **name** 作为参数的 [string of characters](c_strings.md)。当函数被调用时,我们传递一个名字,这个名字在函数内部用来打印“Hello”和每个人的名字。 17 | 18 | ```c 19 | void myFunction(char name[]) { 20 | printf("Hello %s\n", name); 21 | } 22 | 23 | int main() { 24 | myFunction("Liam"); 25 | myFunction("Jenny"); 26 | myFunction("Kenny"); 27 | return 0; 28 | } 29 | 30 | // Hello Liam 31 | // Hello Jenny 32 | // Hello Kenny 33 | ``` 34 | 35 | 当一个 **parameter** 被传递给函数时,它被称为一个 **argument**。 因此,从上面的示例中:`name` 是一个**parameter**,而`Liam`、`Jenny` 和`Anja` 是**arguments**。 36 | 37 | ## 多个参数 38 | 39 | 在函数内部,您可以添加任意数量的参数(parameters): 40 | 41 | ```c 42 | void myFunction(char name[], int age) { 43 | printf("Hello %s. You are %d years old.\n", name, age); 44 | } 45 | 46 | int main() { 47 | myFunction("Liam", 3); 48 | myFunction("Jenny", 14); 49 | myFunction("Anja", 30); 50 | return 0; 51 | } 52 | 53 | // Hello Liam. You are 3 years old. 54 | // Hello Jenny. You are 14 years old. 55 | // Hello Anja. You are 30 years old. 56 | ``` 57 | 58 | 请注意,当您使用多个参数(**parameters**)时,函数调用必须具有与参数(**arguments**)相同数量的参数(**parameters**),并且参数(**arguments**)必须以相同的顺序传递。 59 | 60 | ## 返回值 61 | 62 | 前面示例中使用的 `void` 关键字表示函数不应返回值。 如果希望函数返回值,可以使用数据类型(如`int`或`float`等)代替`void`,并在函数内部使用`return`关键字: 63 | 64 | ```c 65 | int myFunction(int x) { 66 | return 5 + x; 67 | } 68 | 69 | int main() { 70 | printf("Result is: %d", myFunction(3)); 71 | 72 | return 0; 73 | } 74 | 75 | // 输出 8 (5 + 3) 76 | ``` 77 | 78 | 此示例返回具有**两个参数(parameters)**的函数的总和: 79 | 80 | ```c 81 | int myFunction(int x, int y) { 82 | return x + y; 83 | } 84 | 85 | int main() { 86 | printf("Result is: %d", myFunction(5, 3)); 87 | return 0; 88 | } 89 | 90 | // Outputs 8 (5 + 3) 91 | ``` 92 | 93 | 您还可以将结果存储在变量中: 94 | 95 | ```c 96 | int myFunction(int x, int y) { 97 | return x + y; 98 | } 99 | 100 | int main() { 101 | int result = myFunction(5, 3); 102 | printf("Result is = %d", result); 103 | 104 | return 0; 105 | } 106 | // Outputs 8 (5 + 3) 107 | ``` -------------------------------------------------------------------------------- /docs/c_functions_recursion.md: -------------------------------------------------------------------------------- 1 | C 递归 2 | === 3 | 4 | 递归是使函数调用本身的技术。 这种技术提供了一种将复杂问题分解为更容易解决的简单问题的方法。 5 | 6 | 递归可能有点难以理解。 弄清楚它是如何工作的最好方法是尝试它。 7 | 8 | ## 递归示例 9 | 10 | 将两个数字相加很容易,但将一系列数字相加则比较复杂。 在以下示例中,递归用于将一系列数字相加,方法是将其分解为两个数字相加的简单任务: 11 | 12 | ```c 13 | int sum(int k); 14 | 15 | int main() { 16 | int result = sum(10); 17 | printf("%d", result); 18 | return 0; 19 | } 20 | 21 | int sum(int k) { 22 | if (k > 0) { 23 | return k + sum(k - 1); 24 | } else { 25 | return 0; 26 | } 27 | } 28 | ``` 29 | 30 | ## 示例解释 31 | 32 | 当调用 `sum()` 函数时,它会将参数 `k` 添加到所有小于 `k` 的数字的总和中并返回结果。 当 k 变为 0 时,函数只返回 0。运行时,程序按以下步骤操作: 33 | 34 | ```c 35 | 10 + sum(9) 36 | 10 + ( 9 + sum(8) ) 37 | 10 + ( 9 + ( 8 + sum(7) ) ) 38 | ... 39 | 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + sum(0) 40 | 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 41 | ``` 42 | 43 | 由于当 `k` 为 `0` 时函数不会调用自身,所以程序会停在那里并返回结果。 44 | 45 | 开发人员应该非常小心递归,因为很容易陷入编写一个永不终止的函数,或者一个使用过多内存或处理器能力的函数。 但是,如果编写正确,递归可能是一种非常有效且数学上优雅的编程方法。 46 | -------------------------------------------------------------------------------- /docs/c_getstarted.md: -------------------------------------------------------------------------------- 1 | 开始使用 C 2 | === 3 | 4 | 要开始使用 C,您需要做两件事: 5 | 6 | - 用于编写 C 代码的文本编辑器,如记事本 7 | - 编译器,如 GCC,将 C 代码翻译成计算机可以理解的语言 8 | 9 | 有许多文本编辑器和编译器可供选择。 我们介绍几种编辑器和编译环境(见下文)。 10 | 11 | 注意 ⚠️ :Linux 和 Mac 系统可以直接安装 GCC,Windows 系统可以安装 MinGW。 12 | 13 | ## 编辑器 14 | 15 | ### Visual Studio Code 16 | 17 | [![VSCode 下载安装地址](../assets/editer-01.png)](https://code.visualstudio.com) 18 | 19 | VSCode 下载安装地址:https://code.visualstudio.com 20 | 21 | 下载安装好 [VSCode](https://code.visualstudio.com) 后,我们需要安装下面两个插件更方便的支持 C 语言环境。 22 | 23 | - [C/C++ Extension Pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools-extension-pack) 24 | - [Code Runner](https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner) 25 | 26 | ### Sublime Text 3 27 | 28 | [![Sublime Text 下载安装地址](../assets/sublime-01.png)](https://www.sublimetext.com) 29 | 30 | Sublime Text 下载安装地址:https://www.sublimetext.com 31 | 32 | ## C 快速入门 33 | 34 | 如果您不理解下面的代码,请不要担心 —— 我们将在后面的章节中详细讨论。 现在,专注于如何运行代码。 35 | 36 | ### 创建第一个程序 37 | 38 | 让我们创建我们的第一个 C 文件。 39 | 40 | 打开编辑器选择菜单 `File` > `New File` 创建一个空的文本文件。 41 | 42 | 编写以下 C 代码并将文件另存为 `hello.c`(`File` > `Save As`): 43 | 44 | ```c 45 | #include 46 | 47 | int main() { 48 | printf("Hello World!"); 49 | return 0; 50 | } 51 | ``` 52 | 53 | ### 编辑器编译运行 54 | 55 | 在 [Visual Studio Code](https://code.visualstudio.com) 中,它应该如下所示: 56 | 57 | ![](../assets/editer-runcode.png) 58 | 59 | 然后,点击 `Run Code` 以运行(执行)程序。 结果看起来像这样: 60 | 61 | ```bash 62 | [Running] cd "/Users/c-tutorial/example/" && gcc hello.c -o hello && "/Users/c-tutorial/example/"hello 63 | Hello world! 64 | [Done] exited with code=0 in 4.016 seconds 65 | ``` 66 | 67 | 在 Sublime Text 3 中,运行比较简单,打开 `hello.c` 文件,`Tool` > `Build` 选择 `C Single File - Run`,它应该如下所示: 68 | 69 | [![Sublime Text 下载安装地址](../assets/sublime-02.png)](https://www.sublimetext.com) 70 | 71 | ### 命令行编译运行 72 | 73 | 通过命令行进入 `hello.c` 所在目录 74 | 75 | ```bash 76 | cd /Users/c-tutorial/example 77 | ``` 78 | 79 | 使用 `gcc` 编译 `hello.c` 文件, 80 | 81 | ```bash 82 | $ gcc -o hello hello.c 83 | ``` 84 | 85 | 运行成功之后会在当前目录下看到 hello 文件,直接在命令后输入 `./hello` 命令,您将得到如下输出结果: 86 | 87 | ```bash 88 | Hello World 89 | ``` 90 | 91 | ### Docker 运行环境 92 | 93 | 可以简单用 Docker 来安装编译环境,这样在 Windows、MacOS、Linux 下都可以拥有完全相同的编译环境。 94 | 95 | 镜像基于 Alpine Linux 镜像,只有 5MB 镜像,并且包含 C/C++ 编译器(gcc/g++ 包) 96 | 97 | 1) 安装 Docker 98 | 2) 使用 docker pull 命令 99 | ```bash 100 | docker pull frolvlad/alpine-gxx 101 | ``` 102 | 3) 创建 Dockerfile 文件 103 | ```docker 104 | FROM alpine:3.14 105 | RUN apk add --no-cache gcc musl-dev 106 | RUN apk add --no-cache g++ 107 | ``` 108 | 4) 生成本地镜像 109 | ```bash 110 | docker build -t myalpine . 111 | ``` 112 | 5) 运行映像,把当前路径($PWD)映射至容器的 /test 目录,用 gcc 编译程序,exit返回: 113 | ```shell 114 | docker run -it -v$PWD:/test myalpine 115 | root@b1a38bd7107a:/# cd test 116 | root@b1a38bd7107a:/test# gcc -o hello hello.c 117 | Hello World 118 | root@b1a38bd7107a:/test# exit 119 | exit 120 | ``` -------------------------------------------------------------------------------- /docs/c_keywords.md: -------------------------------------------------------------------------------- 1 | C 关键字 2 | === 3 | 4 | C 语言一共有32个关键字,如下表所示: 5 | 6 | 关键字 | 说明 | 关键字 | 说明 7 | ---- | ---- | ---- | ---- 8 | auto | 声明自动变量 | static | 声明静态变量 9 | short | 声明短整型变量或函数 | volatile | 说明变量在程序执行中可被隐含地改变 10 | [int](./c_variables.md) | 声明整型变量或函数 | void | 声明函数无返回值或无参数,声明无类型指针 11 | long | 声明长整型变量或函数 | [if](./c_conditions.md) | 条件语句 12 | [float](./c_variables.md) | 声明浮点型变量或函数 | [else](./c_conditions.md) | 条件语句否定分支(与 if 连用) 13 | double | 声明双精度变量或函数 | [switch](./c_switch.md) | 用于开关语句 14 | [char](./c_strings.md) | 声明字符型变量或函数 | case | 开关语句分支 15 | [struct](./c_structs.md) | 声明结构体变量或函数 | [for](./c_for_loop.md) | 一种循环语句 16 | union | 声明共用数据类型 | do | 循环语句的循环体 17 | [enum](./c_enum.md) | 声明枚举类型 | [while](./c_while_loop.md) | 循环语句的循环条件 18 | typedef | 用以给数据类型取别名 | goto | 无条件跳转语句 19 | [const](./c_constants.md) | 声明只读变量 | [continue](./c_break_continue.md) | 结束当前循环,开始下一轮循环 20 | unsigned | 声明无符号类型变量或函数 | [break](./c_break_continue.md) | 跳出当前循环 21 | signed | 声明有符号类型变量或函数 | default | 开关语句中的“其他”分支 22 | extern | 声明变量是在其他文件正声明 | sizeof | 计算数据类型长度 23 | register | 声明寄存器变量 | return | 子程序返回语句(可以带参数,也可不带参数)循环条件 24 | -------------------------------------------------------------------------------- /docs/c_math.md: -------------------------------------------------------------------------------- 1 | C 数学函数 2 | === 3 | 4 | 还有一个可用的数学函数列表,允许您对数字执行数学任务。 5 | 6 | 要使用它们,您必须在程序中包含 `math.h` **头文件**: 7 | 8 | ```c 9 | #include 10 | ``` 11 | 12 | ## 平方根 13 | 14 | 要找到数字的平方根,请使用 `sqrt()` 函数: 15 | 16 | ```c 17 | printf("%f", sqrt(16)); 18 | ``` 19 | 20 | ## 四舍五入 21 | 22 | `ceil()` 函数将一个数字向上舍入到最接近的整数,而 `floor()` 方法将一个数字向下舍入到最接近的整数,并返回结果: 23 | 24 | ```c 25 | printf("%f", ceil(1.4)); 26 | printf("%f", floor(1.4)); 27 | ``` 28 | 29 | ## Power 30 | 31 | `pow()` 函数返回 *x* 的 *y* 次方 (*xy*): 32 | 33 | ```c 34 | printf("%f", pow(4, 3)); 35 | ``` 36 | 37 | ## 其他数学函数 38 | 39 | 下表列出了其他流行的数学函数(来自 `` 库): 40 | 41 | | 函数 | 描述 Description | 42 | | -------- | --------------------------------------- | 43 | | abs(x) | 返回 x 的绝对值 | 44 | | acos(x) | 返回 x 的反余弦值 | 45 | | asin(x) | 返回 x 的反正弦值 | 46 | | atan(x) | 返回 x 的反正切 | 47 | | cbrt(x) | 返回 x 的立方根 | 48 | | cos(x) | 返回 x 的余弦 | 49 | | exp(x) | 返回 Ex 的值 | 50 | | sin(x) | 返回 x 的正弦值(x 以弧度为单位) | 51 | | tan(x) | 返回角度的正切 | 52 | -------------------------------------------------------------------------------- /docs/c_memory_address.md: -------------------------------------------------------------------------------- 1 | C 内存地址 Memory Address 2 | === 3 | 4 | ## 内存地址 5 | 6 | 在 C 中创建变量时,会为该变量分配一个内存地址。 7 | 8 | 内存地址是变量在计算机上的存储位置。 9 | 10 | 当我们给变量赋值时,它就存储在这个内存地址中。 11 | 12 | 要访问它,请使用引用运算符 (`&`),结果将表示变量的存储位置: 13 | 14 | ```c 15 | int myAge = 43; 16 | printf("%p", &myAge); // 输出: 0x7ffe5367e044 17 | ``` 18 | 19 | **注意:** 内存地址为十六进制形式(`0x..`)。 您可能不会在您的程序中得到相同的结果。 20 | 21 | 您还应该注意,`&myAge` 通常被称为 `指针`。 指针基本上将变量的内存地址存储为其值。 要打印指针值,我们使用 `%p` 格式说明符。 您将在下一章了解更多关于 [指针](./c_pointers.md) 的内容。 22 | 23 | ## 为什么知道内存地址很有用? 24 | 25 | [**Pointers**](./c_pointers.md) 在 C 中很重要,因为它们使您能够操作计算机内存中的数据 - **这可以减少代码并提高性能**。 26 | 27 | 指针是使 C 从其他编程语言中脱颖而出的因素之一,例如 `Python` 和 `Java`。 28 | -------------------------------------------------------------------------------- /docs/c_operators.md: -------------------------------------------------------------------------------- 1 | C 运算符 Operators 2 | === 3 | 4 | ## 运算符 5 | 6 | 运算符用于对变量和值执行操作。 7 | 8 | 在下面的示例中,我们使用 `+` **运算符** 将两个值相加: 9 | 10 | ```c 11 | int myNum = 100 + 50; 12 | ``` 13 | 14 | 尽管 `+` 运算符经常用于将两个值相加,就像上面的示例一样,它也可以用于将一个变量和一个值相加,或者一个变量和另一个变量相加: 15 | 16 | ```c 17 | int sum1 = 100 + 50; // 150 (100 + 50) 18 | int sum2 = sum1 + 250; // 400 (150 + 250) 19 | int sum3 = sum2 + sum2; // 800 (400 + 400) 20 | ``` 21 | C 将运算符分为以下几组: 22 | 23 | * [算术运算符](#算术运算符) (Arithmetic operators) 24 | * [赋值运算符](#赋值运算符) (Assignment operators) 25 | * [比较运算符](#比较运算符) (Comparison operators) 26 | * [逻辑运算符](#逻辑运算符) (Logical operators) 27 | * [位运算符](#位运算符) (Bitwise operators) 28 | 29 | ## 算术运算符 30 | 31 | 算术运算符用于执行常见的数学运算。 32 | 33 | | Operator | Name | Description | Example | 34 | | -------- | -------- | -------- | -------- | 35 | | + | 加 Addition | 将两个值相加 | x + y | 36 | | - | 减 Subtraction | 从另一个值中减去一个值 | x - y | 37 | | \* | 乘 Multiplication | 将两个值相乘 | x \* y | 38 | | / | 除 Division | 将一个值除以另一个 | x / y | 39 | | % | 取模 Modulus | 返回除法余数 | x % y | 40 | | ++ | 增量 Increment | 将变量的值增加 1 | ++x | 41 | | -- | 乘量 Decrement | 将变量的值减 1 | --x | 42 | 43 | ## 赋值运算符 44 | 45 | 赋值运算符用于为变量赋值。 46 | 47 | 在下面的示例中,我们使用 **赋值** 运算符 (`=`) 将值 **10** 分配给名为 **x** 的变量: 48 | 49 | ```c 50 | int x = 10; 51 | ``` 52 | 53 | **加法赋值**运算符 (`+=`) 将值添加到变量: 54 | 55 | ```c 56 | int x = 10; 57 | x += 5; 58 | ``` 59 | 60 | 所有赋值运算符的列表: 61 | 62 | | 符号 | 示例 | 如同 | 63 | | -------- | ------- | ---------- | 64 | | = | x = 5 | x = 5 | 65 | | += | x += 3 | x = x + 3 | 66 | | -= | x -= 3 | x = x - 3 | 67 | | \*= | x \*= 3 | x = x \* 3 | 68 | | /= | x /= 3 | x = x / 3 | 69 | | %= | x %= 3 | x = x % 3 | 70 | | &= | x &= 3 | x = x & 3 | 71 | | \|= | x \|= 3 | x = x \| 3 | 72 | | ^= | x ^= 3 | x = x ^ 3 | 73 | | >>= | x >>= 3 | x = x >> 3 | 74 | | <<= | x <<= 3 | x = x << 3 | 75 | 76 | ## 比较运算符 77 | 78 | 比较运算符用于比较两个值。 79 | 80 | **注意:** 比较的返回值为 true (`1`) 或 false (`0`)。 81 | 82 | 在以下示例中,我们使用 **大于** 运算符 (`>`) 来确定 5 是否大于 3: 83 | 84 | ```c 85 | int x = 5; 86 | int y = 3; 87 | printf("%d", x > y); // 返回 1(真),因为 5 大于 3 88 | ``` 89 | 90 | 所有比较运算符的列表: 91 | 92 | | 符号 | 名称 | 示例 | 93 | | -------- | ------- | ------- | 94 | | == | 等于 | x == y | 95 | | != | 不等于 | x != y | 96 | | > | 大于 | x > y | 97 | | < | 小于 | x < y | 98 | | >= | 大于或等于 | x >= y | 99 | | <= | 小于或等于 | x <= y | 100 | 101 | ## 逻辑运算符 102 | 103 | 逻辑运算符用于确定变量或值之间的逻辑: 104 | 105 | | 符号 | 名称 | 说明 | 示例 | 106 | | -------- | -------- | -------- | -------- | 107 | | && | 与逻辑 | 如果两个语句都为真,则返回真 | x < 5 && x < 10 | 108 | | \|\| | 或逻辑 | 如果其中一个语句为真,则返回真 | x < 5 \|\| x < 4 | 109 | | ! | 非逻辑 | 反转结果,如果结果为真则返回假 | !(x < 5 && x < 10) | 110 | 111 | ## 位运算符 112 | 113 | 运算符 | 描述 | 实例 114 | :- |:- |:- 115 | `&` | 按位与操作,按二进制位进行"与"运算 | `(A & B)` 将得到 `12` 即为 0000 1100 116 | `\|` | 按位或运算符,按二进制位进行"或"运算 | `(A \| B)` 将得到 `61` 即为 0011 1101 117 | `^` | 异或运算符,按二进制位进行"异或"运算 | `(A ^ B)` 将得到 `49` 即为 0011 0001 118 | `~` | 取反运算符,按二进制位进行"取反"运算 | `(~A)` 将得到 `-61` 即为 1100 0011 119 | `<<` | 二进制左移运算符 | `A << 2` 将得到 `240` 即为 1111 0000 120 | `>>` | 二进制右移运算符 | `A >> 2` 将得到 `15` 即为 0000 1111 121 | 122 | 下面的实例,了解 C 语言中所有可用的位运算符 123 | 124 | ```c 125 | #include 126 | 127 | int main() 128 | { 129 | unsigned int a = 60; /* 60 = 0011 1100 */ 130 | unsigned int b = 13; /* 13 = 0000 1101 */ 131 | int c = 0; 132 | 133 | c = a & b; /* 12 = 0000 1100 */ 134 | printf("Line 1 - c 的值是 %d\n", c ); 135 | 136 | c = a | b; /* 61 = 0011 1101 */ 137 | printf("Line 2 - c 的值是 %d\n", c ); 138 | 139 | c = a ^ b; /* 49 = 0011 0001 */ 140 | printf("Line 3 - c 的值是 %d\n", c ); 141 | 142 | c = ~a; /*-61 = 1100 0011 */ 143 | printf("Line 4 - c 的值是 %d\n", c ); 144 | 145 | c = a << 2; /* 240 = 1111 0000 */ 146 | printf("Line 5 - c 的值是 %d\n", c ); 147 | 148 | c = a >> 2; /* 15 = 0000 1111 */ 149 | printf("Line 6 - c 的值是 %d\n", c ); 150 | } 151 | ``` 152 | 153 | 当上面的代码被编译和执行时,它会产生下列结果: 154 | 155 | ```c 156 | Line 1 - c 的值是 12 157 | Line 2 - c 的值是 61 158 | Line 3 - c 的值是 49 159 | Line 4 - c 的值是 -61 160 | Line 5 - c 的值是 240 161 | Line 6 - c 的值是 15 162 | ``` 163 | 164 | ## sizeof 运算符 165 | 166 | 可以使用 `sizeof` 运算符找到数据类型或变量的内存大小(以字节为单位): 167 | 168 | ```c 169 | int myInt; 170 | float myFloat; 171 | double myDouble; 172 | char myChar; 173 | 174 | printf("%lu\n", sizeof(myInt)); 175 | printf("%lu\n", sizeof(myFloat)); 176 | printf("%lu\n", sizeof(myDouble)); 177 | printf("%lu\n", sizeof(myChar)); 178 | ``` -------------------------------------------------------------------------------- /docs/c_output.md: -------------------------------------------------------------------------------- 1 | C 输出(打印文本) 2 | === 3 | 4 | `printf()` 函数用于输出值/打印文本 5 | 6 | ## 格式控制符 7 | 8 | 格式控制符 | 说明 9 | ---- | ---- 10 | `%c` | 输出一个单一的字符 11 | `%hd` `%d` `%ld` | 以十进制、有符号的形式输出 short、int、long 类型的整数 12 | `%hu` `%u` `%lu` | 以十进制、无符号的形式输出 short、int、long 类型的整数 13 | `%ho` `%o` `%lo` | 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数 14 | `%#ho` `%#o` `%#lo` | 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数 15 | `%hx` `%x` `%lx`
`%hX` `%X` `%lX` | 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。 16 | `%#hx` `%#x` `%#lx`
`%#hX` `%#X` `%#lX` | 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。 17 | `%f` `%lf` | 以十进制的形式输出 float` `、double 类型的小数 18 | `%e` `%le` `%E` `%lE` | 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。 19 | `%g` `%lg` `%G` `%lG` | 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。 20 | `%s` | 输出一个字符串 21 | 22 | ```c 23 | #include 24 | 25 | int main() { 26 | printf("Hello World!"); 27 | return 0; 28 | } 29 | ``` 30 | 31 | 您可以根据需要添加任意数量的 `printf()` 函数。 但是,请注意,它不会在输出末尾插入新行: 32 | 33 | ```c 34 | #include 35 | 36 | int main() { 37 | printf("Hello World!"); 38 | printf("I am learning C."); 39 | return 0; 40 | } 41 | ``` 42 | 43 | ### `%d` 输出整数 44 | 45 | ```c 46 | #include 47 | 48 | int main() 49 | { 50 | int testInteger = 5; 51 | printf("Number = %d", testInteger); 52 | return 0; 53 | } 54 | ``` 55 | 56 | 输出 `Number = 5` 57 | 58 | ### `%f` 输出浮点型数据 59 | 60 | ```c 61 | #include 62 | int main() 63 | { 64 | float f; 65 | printf("Enter a number: "); 66 | // %f 匹配浮点型数据 67 | scanf("%f", &f); 68 | printf("Value = %f", f); 69 | return 0; 70 | } 71 | ``` 72 | 73 | ## short/int/long 74 | 75 | | | short | int | long | 76 | | ---- | ---- | ---- | ---- | 77 | | 8 进制 | `%ho` | `%o` | `%lo` | 78 | | 10 进制 | `%hd` | `%d` | `%ld` | 79 | | 16 进制 | `%hx` 或者 `%hX` | `%x` 或者 `%X` | `%lx` 或者 `%lX` | 80 | 81 | ```c 82 | short a = 0b1010110; // 2 进制数字 83 | int b = 02713; // 8 进制数字 84 | long c = 0X1DAB83; // 16 进制数字 85 | 86 | printf("a=%ho, b=%o, c=%lo\n", a, b, c); // 以 8 进制形似输出 87 | // a=126, b=2713, c=7325603 88 | printf("a=%hd, b=%d, c=%ld\n", a, b, c); // 以 10 进制形式输出 89 | // a=86, b=1483, c=1944451 90 | printf("a=%hx, b=%x, c=%lx\n", a, b, c); // 以 16 进制形式输出(字母小写) 91 | // a=56, b=5cb, c=1dab83 92 | printf("a=%hX, b=%X, c=%lX\n", a, b, c); // 以 16 进制形式输出(字母大写) 93 | // a=56, b=5CB, c=1DAB83 94 | ``` 95 | 96 | ## 控制空格数 97 | 98 | ```c 99 | #include 100 | int main() 101 | { 102 | int a1=20, a2=345, a3=700, a4=22; 103 | int b1=56720, b2=9999, b3=20098, b4=2; 104 | int c1=233, c2=205, c3=1, c4=6666; 105 | int d1=34, d2=0, d3=23, d4=23006783; 106 | printf("%-9d %-9d %-9d %-9d\n", a1, a2, a3, a4); 107 | printf("%-9d %-9d %-9d %-9d\n", b1, b2, b3, b4); 108 | printf("%-9d %-9d %-9d %-9d\n", c1, c2, c3, c4); 109 | printf("%-9d %-9d %-9d %-9d\n", d1, d2, d3, d4); 110 | return 0; 111 | } 112 | ``` 113 | 114 | 输出结果: 115 | 116 | ```bash 117 | 20 345 700 22 118 | 56720 9999 20098 2 119 | 233 205 1 6666 120 | 34 0 23 23006783 121 | ``` 122 | 123 | `%-9d` 中,`d` 表示以 10 进制输出,`9` 表示最少占 `9` 个字符的宽度,宽度不足以空格补齐,`-` 表示左对齐。综合起来,`%-9d` 表示以 10 进制输出,左对齐,宽度最小为 `9` 个字符。大家可以亲自试试 `%9d` 的输出效果。 124 | 125 | ## 标志字符 126 | 127 | - `-` 表示左对齐。如果没有,就按照默认的对齐方式,默认一般为右对齐。 128 | - `+` 用于整数或者小数,表示输出符号(正负号)。如果没有,那么只有负数才会输出符号。 129 | - `空格` 用于整数或者小数,输出值为正时冠以空格,为负时冠以负号。 130 | - `#` 对于八进制(`%o`)和十六进制(`%x` / `%X`)整数,`#` 表示在输出时添加前缀;八进制的前缀是 `0`,十六进制的前缀是 `0x` / `0X`。对于小数(`%f` / `%e` / `%g`),`#` 表示强迫输出小数点。如果没有小数部分,默认是不输出小数点的,加上 `#` 以后,即使没有小数部分也会带上小数点。 131 | 132 | ```c 133 | #include 134 | int main(){ 135 | int m = 192, n = -943; 136 | float f = 84.342; 137 | printf("m=%10d, m=%-10d\n", m, m); // 演示 - 的用法 138 | printf("m=%+d, n=%+d\n", m, n); // 演示 + 的用法 139 | printf("m=% d, n=% d\n", m, n); // 演示空格的用法 140 | printf("f=%.0f, f=%#.0f\n", f, f); // 演示 # 的用法 141 | return 0; 142 | } 143 | ``` 144 | 145 | 运行结果: 146 | 147 | ```bash 148 | m= 192, m=192 # 当以%10d输出 m 时,是右对齐, 149 | # 所以在 192 前面补七个空格; 150 | # 当以%-10d输出 m 时,是左对齐,所以在 192 后面补七个空格。 151 | 152 | m=+192, n=-943 # m 是正数,以 %+d 输出时要带上正号;n 是负数,以%+d输出时要带上负号。 153 | 154 | m= 192, n=-943 # m 是正数,以 % d 输出时要在前面加空格;n 是负数,以% d输出时要在前面加负号。 155 | 156 | f=84, f=84. # %.0f表示保留 0 位小数,也就是只输出整数部分,不输出小数部分。 157 | # 默认情况下,这种输出形式是不带小数点的,但是如果有了#标志, 158 | # 那么就要在整数的后面“硬加上”一个小数点,以和纯整数区分开。 159 | ``` 160 | 161 | ## 格式控制符 162 | 163 | ``` 164 | %[flag][width][.precision]type 165 | ``` 166 | 167 | - `[ ]` 表示此处的内容可有可无,是可以省略的。 168 | - `type` (必须有)表示输出类型,比如 `%d`、`%f`、`%c`、`%lf`,`type` 就分别对应 `d`、`f`、`c`、`lf`;再如,`%-9d` 中 `type` 对应 `d`。 169 | - `width` 表示最小输出宽度,也就是至少占用几个字符的位置;例如,`%-9d` 中 `width` 对应 `9`,表示输出结果最少占用 `9` 个字符的宽度。 170 | 171 | ```c 172 | #include 173 | int main(){ 174 | int n = 234; 175 | float f = 9.8; 176 | char c = '@'; 177 | char *str = "https://github.com/jaywcjlove/c-tutorial"; 178 | printf("%10d%12f%4c%8s", n, f, c, str); 179 | return 0; 180 | } 181 | ``` 182 | 183 | 运行结果: 184 | 185 | ``` 186 | 234 9.800000 @https://github.com/jaywcjlove/c-tutorial 187 | ``` 188 | 189 | 对输出结果的说明: 190 | 191 | - `n` 的指定输出宽度为 10,234 的宽度为 3,所以前边要补上 7 个空格。 192 | - `f` 的指定输出宽度为 12,9.800000 的宽度为 8,所以前边要补上 4 个空格。 193 | - `str` 的指定输出宽度为 8,"https://github.com/jaywcjlove/c-tutorial" 的宽度为 `40`,超过了 8,所以指定输出宽度不再起作用,而是按照 `str` 的实际宽度输出。 194 | 195 | ## 输出精度/宽度 196 | 197 | ```c 198 | #include 199 | int main(){ 200 | int n = 123456; 201 | double f = 882.923672; 202 | char *str = "abcdefghi"; 203 | printf("n: %.9d %.4d\n", n, n); 204 | printf("f: %.2lf %.4lf %.10lf\n", f, f, f); 205 | printf("str: %.5s %.15s\n", str, str); 206 | return 0; 207 | } 208 | ``` 209 | 210 | 运行结果: 211 | 212 | ``` 213 | n: 000123456 123456 214 | f: 882.92 882.9237 882.9236720000 215 | str: abcde abcdefghi 216 | ``` 217 | 对输出结果的说明: 218 | 219 | - 对于 `n`,`.precision` 表示最小输出宽度。n 本身的宽度为 6,当 `precision` 为 9 时,大于 6,要在 n 的前面补 3 个 0;当 `precision` 为 4 时,小于 6,不再起作用。 220 | - 对于 `f`,`.precision` 表示输出精度。f 的小数部分有 6 位数字,当 `precision` 为 2 或者 4 时,都小于 6,要按照四舍五入的原则截断小数;当 precision 为 10 时,大于 6,要在小数的后面补四个 0。 221 | - 对于 `str`,`.precision` 表示最大输出宽度。`str` 本身的宽度为 9,当 `precision` 为 5 时,小于 9,要截取 str 的前 5 个字符;当 precision 为 15 时,大于 9,不再起作用。 -------------------------------------------------------------------------------- /docs/c_pointers.md: -------------------------------------------------------------------------------- 1 | C 指针 Pointers 2 | === 3 | 4 | ## 创建指针 5 | 6 | 您从上一章中了解到,我们可以使用引用运算符 `&` 获取变量的**内存地址**: 7 | 8 | ```c 9 | int myAge = 43; // 一个 int 变量 10 | 11 | printf("%d", myAge); // 输出 myAge (43) 的值 12 | printf("%p", &myAge); // 输出myAge的内存地址(0x7ffe5367e044) 13 | ``` 14 | 15 | 在上面的示例中,`&myAge` 也称为**指针**。 16 | 17 | **指针** 是一个变量,它存储另一个变量的内存地址作为其值。 18 | 19 | **指针变量** **指向同一类型的数据类型**(如 `int`),并使用 `*` 运算符创建。 您正在使用的变量的地址分配给指针: 20 | 21 | ```c 22 | int myAge = 43; // 一个 int 变量 23 | int* ptr = &myAge; // 一个名为 ptr 的指针变量,用于存储 myAge 的地址 24 | 25 | // 输出 myAge (43) 的值 26 | printf("%d\n", myAge); 27 | 28 | // 输出myAge的内存地址(0x7ffe5367e044) 29 | printf("%p\n", \&myAge); 30 | 31 | // 用指针(0x7ffe5367e044)输出myAge的内存地址 32 | printf("%p\n", ptr); 33 | ``` 34 | 35 | #### 示例说明 36 | 37 | 创建一个名为 `ptr` 的指针变量,它**指向**一个 `int` 变量(`myAge`)。 请注意,指针的类型必须与您正在使用的变量的类型相匹配。 38 | 39 | 使用 `&` 运算符存储 `myAge` 变量的内存地址,并将其分配给指针。 40 | 41 | 现在,`ptr` 保存了`myAge` 的内存地址的值。 42 | 43 | ## 取消引用 44 | 45 | 在上面的示例中,我们使用指针变量来获取变量的内存地址(与 `&` **reference ** 运算符一起使用)。 46 | 47 | 但是,您也可以使用 `*` 运算符(**dereference ** 运算符)获取指针指向的变量的值: 48 | 49 | ```c 50 | int myAge = 43; // 变量声明 51 | int* ptr = &myAge; // 指针声明 52 | 53 | // 参考:用指针输出 myAge 的内存地址(0x7ffe5367e044) 54 | printf("%p\n", ptr); 55 | 56 | // 取消引用:用指针输出 myAge 的值 (43) 57 | printf("%d\n", *ptr); 58 | ``` 59 | 60 | 请注意,`*` 符号在这里可能会造成混淆,因为它在我们的代码中做了两件不同的事情: 61 | 62 | * 在声明 (`int* ptr`) 中使用时,它会创建一个**指针变量**。 63 | * 在声明中不使用时,它充当**解引用运算符**。 64 | 65 | ## 我为什么要学习指针? 66 | 67 | 指针在 C 语言中很重要,因为它们使您能够操作计算机内存中的数据——这可以减少代码并提高性能。 68 | 69 | ## 三种声明指针变量的方式 70 | 71 | ```c 72 | int* myNum; // 最常被使用 73 | int *myNum; 74 | int * myNum; 75 | ``` -------------------------------------------------------------------------------- /docs/c_preprocessors.md: -------------------------------------------------------------------------------- 1 | C 预处理器 2 | === 3 | 4 | C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。 5 | 6 | ## 预处理器指令 7 | 8 | 所有的预处理器命令都是以井号(`#`)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。下面列出了所有重要的预处理器指令: 9 | 10 | 指令 | 描述 11 | ---- | ---- 12 | `#define` | 定义宏 13 | `#include` | 包含一个源代码文件 14 | `#undef` | 取消已定义的宏 15 | `#ifdef` | 如果宏已经定义,则返回真 16 | `#ifndef` | 如果宏没有定义,则返回真 17 | `#if` | 如果给定条件为真,则编译下面代码 18 | `#else` | `#if` 的替代方案 19 | `#elif` | 如果前面的 `#if` 给定条件不为真,当前条件为真,则编译下面代码 20 | `#endif` | 结束一个 `#if……#else` 条件编译块 21 | `#error` | 当遇到标准错误时,输出错误消息 22 | `#pragma` | 使用标准化方法,向编译器发布特殊的命令到编译器中 23 | 24 | ## 预处理器实例 25 | 26 | 分析下面的实例来理解不同的指令。 27 | 28 | ```c 29 | #define MAX_ARRAY_LENGTH 20 30 | ``` 31 | 32 | 这个指令告诉 `CPP` 把所有的 `MAX_ARRAY_LENGTH` 替换为 `20`。使用 `#define` 定义常量来增强可读性。 33 | 34 | ```c 35 | #include 36 | #include "myheader.h" 37 | ``` 38 | 39 | 这些指令告诉 `CPP` 从系统库中获取 `stdio.h`,并添加文本到当前的源文件中。下一行告诉 CPP 从本地目录中获取 `myheader.h`,并添加内容到当前的源文件中。 40 | 41 | ```c 42 | #undef FILE_SIZE 43 | #define FILE_SIZE 42 44 | ``` 45 | 46 | 这个指令告诉 `CPP` 取消已定义的 `FILE_SIZE`,并定义它为 `42`。 47 | 48 | ```c 49 | #ifndef MESSAGE 50 | #define MESSAGE "You wish!" 51 | #endif 52 | ``` 53 | 54 | 这个指令告诉 `CPP` 只有当 `MESSAGE` 未定义时,才定义 `MESSAGE`。 55 | 56 | ```c 57 | #ifdef DEBUG 58 | /* 您的调试语句在这里 */ 59 | #endif 60 | ``` 61 | 62 | 这个指令告诉 `CPP` 如果定义了 `DEBUG`,则执行处理语句。在编译时,如果您向 `gcc` 编译器传递了 `DDEBUG` 开关量,这个指令就非常有用。它定义了 `DEBUG`,您可以在编译期间随时开启或关闭调试。 63 | 64 | ## 预定义宏 65 | 66 | ANSI C 定义了许多宏。在编程中您可以使用这些宏,但是不能直接修改这些预定义的宏。 67 | 68 | 宏 | 描述 69 | ---- | ---- 70 | `__DATE__` | 当前日期,一个以 "MMM DD YYYY" 格式表示的字符常量。 71 | `__TIME__` | 当前时间,一个以 "HH:MM:SS" 格式表示的字符常量。 72 | `__FILE__` | 这会包含当前文件名,一个字符串常量。 73 | `__LINE__` | 这会包含当前行号,一个十进制常量。 74 | `__STDC__` | 当编译器以 `ANSI` 标准编译时,则定义为 `1`。 75 | 76 | ```c 77 | #include 78 | 79 | int main() { 80 | printf("File :%s\n", __FILE__); 81 | printf("Date :%s\n", __DATE__); 82 | printf("Time :%s\n", __TIME__); 83 | printf("Line :%d\n", __LINE__); 84 | printf("ANSI :%d\n", __STDC__); 85 | } 86 | ``` 87 | 88 | ## 预处理器运算符 89 | 90 | C 预处理器提供了下列的运算符来帮助您创建宏: 91 | 92 | ### 宏延续运算符(\) 93 | 94 | 一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符 `\`。例如: 95 | 96 | ```c 97 | #define message_for(a, b) \ 98 | printf(#a " and " #b ": We love you!\n") 99 | ``` 100 | 101 | ### 字符串常量化运算符(#) 102 | 103 | 在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符 `#`。在宏中使用的该运算符有一个特定的参数或参数列表。例如: 104 | 105 | ```c 106 | #include 107 | 108 | #define message_for(a, b) \ 109 | printf(#a " and " #b ": We love you!\n") 110 | 111 | int main(void) { 112 | message_for(Carole, Debra); 113 | return 0; 114 | } 115 | ``` 116 | 117 | 当上面的代码被编译和执行时,它会产生下列结果: 118 | 119 | ``` 120 | Carole and Debra: We love you! 121 | ``` 122 | 123 | ### 标记粘贴运算符(##) 124 | 125 | 宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。例如: 126 | 127 | ```c 128 | #include 129 | 130 | #define tokenpaster(n) printf ("token" #n " = %d", token##n) 131 | 132 | int main(void){ 133 | int token34 = 40; 134 | 135 | tokenpaster(34); 136 | return 0; 137 | } 138 | ``` 139 | 140 | 当上面的代码被编译和执行时,它会产生下列结果: 141 | 142 | ```c 143 | token34 = 40 144 | ``` 145 | 146 | 这是怎么发生的,因为这个实例会从编译器产生下列的实际输出: 147 | 148 | ```c 149 | printf ("token34 = %d", token34); 150 | ``` 151 | 152 | 这个实例演示了 `token##n` 会连接到 `token34` 中,在这里,我们使用了**字符串常量化运算符(#)**和**标记粘贴运算符(##)**。 153 | 154 | ### defined() 运算符 155 | 156 | 预处理器 `defined` 运算符是用在常量表达式中的,用来确定一个标识符是否已经使用 `#define` 定义过。如果指定的标识符已定义,则值为真(非零)。如果指定的标识符未定义,则值为假(零)。下面的实例演示了 `defined()` 运算符的用法: 157 | 158 | ```c 159 | #include 160 | 161 | #if !defined (MESSAGE) 162 | #define MESSAGE "You wish!" 163 | #endif 164 | 165 | int main(void) { 166 | printf("Here is the message: %s\n", MESSAGE); 167 | return 0; 168 | } 169 | ``` 170 | 171 | 当上面的代码被编译和执行时,它会产生下列结果: 172 | 173 | ``` 174 | Here is the message: You wish! 175 | ``` 176 | 177 | ## 参数化的宏 178 | 179 | CPP 一个强大的功能是可以使用参数化的宏来模拟函数。例如,下面的代码是计算一个数的平方: 180 | 181 | ```c 182 | int square(int x) { 183 | return x * x; 184 | } 185 | ``` 186 | 187 | 我们可以使用宏重写上面的代码,如下: 188 | 189 | ```c 190 | #define square(x) ((x) * (x)) 191 | ``` 192 | 193 | 在使用带有参数的宏之前,必须使用 `#define` 指令定义。参数列表是括在圆括号内,且必须紧跟在宏名称的后边。宏名称和左圆括号之间不允许有空格。例如: 194 | 195 | ```c 196 | #include 197 | 198 | #define MAX(x,y) ((x) > (y) ? (x) : (y)) 199 | 200 | int main(void) { 201 | printf("Max between 20 and 10 is %d\n", MAX(10, 20)); 202 | return 0; 203 | } 204 | ``` 205 | 206 | 当上面的代码被编译和执行时,它会产生下列结果: 207 | 208 | ```c 209 | Max between 20 and 10 is 20 210 | ``` -------------------------------------------------------------------------------- /docs/c_strings.md: -------------------------------------------------------------------------------- 1 | C 字符串 Strings 2 | === 3 | 4 | 字符串用于存储文本/字符。 5 | 6 | 例如,“Hello World”是一个字符串。 7 | 8 | 与许多其他编程语言不同,C 没有 **String 类型** 来轻松创建字符串变量。但是,您可以使用 `char` 类型并创建一个字符 [array](c_arrays.md) 以在 C 中创建一个字符串: 9 | 10 | ```c 11 | char greetings[] = "Hello World!"; 12 | ``` 13 | 14 | 请注意,您必须使用双引号。 15 | 16 | 要输出字符串,您可以使用 [`printf()`](./c_output.md) 函数和格式说明符 `%s` 来告诉 C 我们现在正在处理字符串: 17 | 18 | ```c 19 | char greetings[] = "Hello World!"; 20 | printf("%s", greetings); 21 | ``` 22 | 23 | ## 访问字符串 24 | 25 | 由于字符串实际上是 C 中的数组,因此您可以通过在方括号 `[]` 中引用其索引号来访问字符串。 26 | 27 | 此示例打印 **greetings** 中的**第一个字符 (0)**: 28 | 29 | ```c 30 | char greetings[] = "Hello World!"; 31 | printf("%c", greetings[0]); 32 | ``` 33 | 34 | 请注意,我们必须使用 `%c` 格式说明符来打印**单个字符**。 35 | 36 | ## 修改字符串 37 | 38 | 要更改字符串中特定字符的值,请参考索引号,并使用**单引号**: 39 | 40 | ```c 41 | char greetings[] = "Hello World!"; 42 | greetings[0] = 'J'; 43 | printf("%s", greetings); 44 | // 输出 "Jello World!" 而不是 "Hello World!" 45 | ``` 46 | 47 | ## 另一种创建字符串的方法 48 | 49 | 在上面的示例中,我们使用 “字符串文字(string literal)” 来创建字符串变量。 这是在 C 中创建字符串的最简单方法。 50 | 51 | 您还应该注意,您可以使用一组字符创建一个字符串。 此示例将产生与上述示例相同的结果: 52 | 53 | ```c 54 | char greetings[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0'}; 55 | printf("%s", greetings); 56 | ``` 57 | 58 | **为什么我们在末尾包含 `\0` 字符?** 这被称为 “空终止字符(null termininating character)”,在使用此方法创建字符串时必须包含。 它告诉 C 这是字符串的结尾。 59 | 60 | ## 差异 61 | 62 | 两种创建字符串的方法之间的区别在于,第一种方法更容易编写,并且您不必包含 `\0` 字符,因为 C 会为您完成。 63 | 64 | 您应该注意,两个数组的大小是相同的:它们都有 **13 个字符**(顺便说一下,空格也算作一个字符),包括 `\0` 字符: 65 | 66 | ```c 67 | char greetings[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0'}; 68 | char greetings2[] = "Hello World!"; 69 | 70 | printf("%lu\n", sizeof(greetings)); // 输出 13 71 | printf("%lu\n", sizeof(greetings2)); // 输出 13 72 | ``` -------------------------------------------------------------------------------- /docs/c_structs.md: -------------------------------------------------------------------------------- 1 | C Structures (structs) 2 | === 3 | 4 | 结构(也称为结构)是一种将多个相关变量组合到一个位置的方法。 结构中的每个变量都称为结构的**成员**。 5 | 6 | 与 [array](c_arrays.md) 不同,结构可以包含许多不同的数据类型(int、float、char 等)。 7 | 8 | ## 创建结构 9 | 10 | 您可以使用 `struct` 关键字创建结构,并在花括号内声明其每个成员: 11 | 12 | ```c 13 | struct MyStructure { // 结构声明 14 | int myNum; // 成员(int 变量) 15 | char myLetter; // 成员(char 变量) 16 | }; // 用分号结束结构 17 | ``` 18 | 19 | 要访问该结构,您必须为其创建一个变量。 20 | 21 | 在 `main()` 方法中使用 `struct` 关键字,后跟结构的名称,然后是结构变量的名称: 22 | 23 | 创建一个名为 `s1` 的结构变量: 24 | 25 | ```c 26 | struct myStructure { 27 | int myNum; 28 | char myLetter; 29 | }; 30 | 31 | int main() { 32 | struct myStructure s1; 33 | return 0; 34 | } 35 | ``` 36 | 37 | ## 访问结构成员 38 | 39 | 要访问结构的成员,请使用点语法 (`.`): 40 | 41 | ```c 42 | // 创建一个名为 myStructure 的结构 43 | struct myStructure { 44 | int myNum; 45 | char myLetter; 46 | }; 47 | 48 | int main() { 49 | // 创建一个名为 **s1** 的 myStructure 结构变量 50 | struct myStructure s1; 51 | 52 | // 为 s1 的成员赋值 53 | s1.myNum = 13; 54 | s1.myLetter = 'B'; 55 | 56 | // 打印值 57 | printf("My number: %d\n", s1.myNum); 58 | printf("My letter: %c\n", s1.myLetter); 59 | 60 | return 0; 61 | } 62 | ``` 63 | 64 | 现在,您只需使用一个结构即可轻松创建具有不同值的多个结构变量: 65 | 66 | 67 | ```c 68 | // 创建不同的结构变量 69 | struct myStructure s1; 70 | struct myStructure s2; 71 | 72 | // 为不同的结构变量赋值 73 | s1.myNum = 13; 74 | s1.myLetter = 'B'; 75 | 76 | s2.myNum = 20; 77 | s2.myLetter = 'C'; 78 | ``` 79 | 80 | ## 结构中的字符串呢? 81 | 82 | 请记住,C 中的字符串实际上是一个字符数组,不幸的是,您不能像这样为数组赋值: 83 | 84 | ```c 85 | struct myStructure { 86 | int myNum; 87 | char myLetter; 88 | char myString[30]; // String 89 | }; 90 | 91 | int main() { 92 | struct myStructure s1; 93 | 94 | // 试图为字符串赋值 95 | s1.myString = "Some text"; 96 | 97 | // 尝试打印值 98 | printf("My string: %s", s1.myString); 99 | 100 | return 0; 101 | } 102 | ``` 103 | 104 | 105 | 会出现错误: 106 | 107 | ```bash 108 | prog.c:12:15: error: assignment to expression with array type 109 | ``` 110 | 111 | 112 | 但是,有一个解决方案! 您可以使用 `strcpy()` 函数并将值分配给 `s1.myString`,如下所示: 113 | 114 | ```c 115 | struct myStructure { 116 | int myNum; 117 | char myLetter; 118 | char myString[30]; // String 119 | }; 120 | 121 | int main() { 122 | struct myStructure s1; 123 | 124 | // 使用 strcpy 函数为字符串赋值 125 | strcpy(s1.myString, "Some text"); 126 | 127 | // 打印值 128 | printf("My string: %s", s1.myString); 129 | 130 | return 0; 131 | } 132 | ``` 133 | 134 | 结果: 135 | 136 | `My string: Some text` 137 | 138 | ## 更简单的语法 139 | 140 | 您还可以在声明时在一行中为结构变量的成员赋值。 141 | 142 | 只需将值插入花括号 `{}` 内的逗号分隔列表中。 请注意,您不必通过这种技术对字符串值使用 `strcpy()` 函数: 143 | 144 | ```c 145 | // 创建结构 146 | struct myStructure { 147 | int myNum; 148 | char myLetter; 149 | char myString[30]; 150 | }; 151 | 152 | int main() { 153 | // 创建一个结构变量并为其赋值 154 | struct myStructure s1 = {13, 'B', "Some text"}; 155 | 156 | // 打印值 157 | printf("%d %c %s", s1.myNum, s1.myLetter, s1.myString); 158 | 159 | return 0; 160 | } 161 | ``` 162 | 163 | **注意:** 插入值的顺序必须与结构中声明的变量类型的顺序相匹配(13 表示 int,'B' 表示 char 等)。 164 | 165 | ## 复制结构 166 | 167 | 您还可以将一种结构分配给另一种结构。 168 | 169 | 在以下示例中,将 s1 的值复制到 s2: 170 | 171 | ```c 172 | struct myStructure s1 = {13, 'B', "Some text"}; 173 | struct myStructure s2; 174 | s2 = s1; 175 | ``` 176 | 177 | 178 | ## 修改值 179 | 180 | 如果要更改/修改值,可以使用点语法 (`.`)。 181 | 182 | 要修改字符串值,`strcpy()` 函数再次很有用: 183 | 184 | ```c 185 | struct myStructure { 186 | int myNum; 187 | char myLetter; 188 | char myString[30]; 189 | }; 190 | 191 | int main() { 192 | // 创建一个结构变量并为其赋值 193 | struct myStructure s1 = {13, 'B', "Some text"}; 194 | 195 | // 修改值 196 | s1.myNum = 30; 197 | s1.myLetter = 'C'; 198 | strcpy(s1.myString, "Something else"); 199 | 200 | // 打印值 201 | printf("%d %c %s", s1.myNum, s1.myLetter, s1.myString); 202 | 203 | return 0; 204 | } 205 | ``` 206 | 207 | 当您复制结构值时,修改值特别有用: 208 | 209 | ```c 210 | // 创建一个结构变量并为其赋值 211 | struct myStructure s1 = {13, 'B', "Some text"}; 212 | 213 | // 创建另一个结构变量 214 | struct myStructure s2; 215 | 216 | // 将 s1 值复制到 s2 217 | s2 = s1; 218 | 219 | // 更改 s2 值 220 | s2.myNum = 30; 221 | s2.myLetter = 'C'; 222 | strcpy(s2.myString, "Something else"); 223 | 224 | // 打印值 225 | printf("%d %c %s\n", s1.myNum, s1.myLetter, s1.myString); 226 | printf("%d %c %s\n", s2.myNum, s2.myLetter, s2.myString); 227 | ``` 228 | 229 | **好的,那么,结构如何有用?** 230 | 231 | 想象一下,您必须编写一个程序来存储有关汽车的不同信息,例如品牌、型号和年份。 结构的优点在于您可以创建一个“汽车模板”并将其用于您制造的每辆汽车。 请参阅下面的真实示例。 232 | 233 | ## 现实生活中的例子 234 | 235 | 使用一个结构来存储关于 Cars 的不同信息: 236 | 237 | ```c 238 | struct Car { 239 | char brand[50]; 240 | char model[50]; 241 | int year; 242 | }; 243 | 244 | int main() { 245 | struct Car car1 = {"BMW", "X5", 1999}; 246 | struct Car car2 = {"Ford", "Mustang", 1969}; 247 | struct Car car3 = {"Toyota", "Corolla", 2011}; 248 | 249 | printf("%s %s %d\n", car1.brand, car1.model, car1.year); 250 | printf("%s %s %d\n", car2.brand, car2.model, car2.year); 251 | printf("%s %s %d\n", car3.brand, car3.model, car3.year); 252 | 253 | return 0; 254 | } 255 | ``` -------------------------------------------------------------------------------- /docs/c_switch.md: -------------------------------------------------------------------------------- 1 | C Switch 2 | === 3 | 4 | ## Switch 语句 5 | 6 | 您可以使用 `switch` 语句,而不是编写 **许多** `if..else` 语句。 7 | 8 | `switch` 语句选择要执行的许多代码块之一: 9 | 10 | ### 语法 11 | 12 | ```c 13 | switch(表达式) { 14 | case 整型数值1: 15 | // 代码块 1 16 | break; 17 | case 整型数值2: 18 | // 代码块 2 19 | break; 20 | default: 21 | // 代码块 3 22 | } 23 | ``` 24 | 25 | 这是它的工作原理: 26 | 27 | * `switch` 表达式被计算一次 28 | * 将表达式的值与每个 `case` 的值进行比较 29 | * 如果匹配,则执行关联的代码块 30 | * `break` 语句跳出 switch 块并停止执行 31 | * `default` 语句是可选的,指定在没有大小写匹配时运行的一些代码 32 | 33 | 下面的示例使用工作日编号来计算工作日名称: 34 | 35 | ```c 36 | int day = 4; 37 | switch (day) { 38 | case 1: 39 | printf("周一"); 40 | break; 41 | case 2: 42 | printf("周二"); 43 | break; 44 | case 3: 45 | printf("周三"); 46 | break; 47 | case 4: 48 | printf("周四"); 49 | break; 50 | case 5: 51 | printf("周五"); 52 | break; 53 | case 6: 54 | printf("周六"); 55 | break; 56 | case 7: 57 | printf("周日"); 58 | break; 59 | } 60 | // 输出 -> "周四" (day 4) 61 | ``` 62 | 63 | ## 中断关键字 break 64 | 65 | 当 C 到达一个 `break` 关键字时,它会跳出 `switch` 块。 66 | 67 | 这将停止在块内执行更多代码和案例测试。 68 | 69 | 找到匹配项并完成工作后,就该休息一下了。 无需进行更多测试。 70 | 71 | 中断可以节省大量执行时间,因为它“忽略”了 switch 块中所有其余代码的执行。 72 | 73 | ## 默认关键字 default 74 | 75 | `default` 关键字指定在没有大小写匹配时运行的一些代码: 76 | 77 | ```c 78 | int day = 4; 79 | 80 | switch (day) { 81 | case 6: 82 | printf("今天是星期六"); 83 | break; 84 | case 7: 85 | printf("今天是星期日"); 86 | break; 87 | default: 88 | printf("期待周末"); 89 | } 90 | 91 | // 输出 -> "期待周末" 92 | ``` 93 | 94 | **注意:** `switch` 中的最后一条语句必须使用 `default` 关键字,并且不需要 `break`。`default` 不是必须的。当没有 `default` 时,如果所有 `case` 都匹配失败,那么就什么都不执行。 95 | 96 | ## 关键字 case 97 | 98 | ```c 99 | case 10: printf("..."); break; // ✅ 💯 正确 100 | case 8+9: printf("..."); break; // ✅ 💯 正确 101 | case 'A': printf("..."); break; // ✅ 💯 正确,字符和整数可以相互转换 102 | case 'A'+19: printf("..."); break; // ✅ 💯 正确,字符和整数可以相互转换 103 | case 9.5: printf("..."); break; // ❌ 错误,不能为小数 104 | case a: printf("..."); break; // ❌ 错误,不能包含变量 105 | case a+10: printf("..."); break; // ❌ 错误,不能包含变量 106 | ``` 107 | -------------------------------------------------------------------------------- /docs/c_syntax.md: -------------------------------------------------------------------------------- 1 | C 语法 2 | === 3 | 4 | C 语言规定了源代码中每个词汇、语句的含义,也规定了它们该如何组织在一起,这就是语法(Syntax)。您已经在 `开始` 章节中看到以下代码。 让我们分解它以更好地理解它: 5 | 6 | ```c 7 | #include 8 | 9 | int main() { 10 | printf("Hello World!"); 11 | return 0; 12 | } 13 | ``` 14 | 15 | **示例说明** 16 | 17 | 第 1 行:`#include ` 是一个头文件库,可让我们使用输入和输出函数,例如 `printf()`(在第 4 行中使用)。头文件向 `C++` 程序添加功能。 18 | 19 | 第 2 行:空行。 `C` 忽略空格。 但是我们使用它来使代码更具可读性。 20 | 21 | 第 3 行:另一个总是出现在 `C` 程序中的东西是 `main()`。 这称为函数。 其大括号 `{}` 内的任何代码都将被执行。 22 | 23 | 第 4 行:`printf()` 是用于将文本输出/打印到屏幕的函数。 在示例中,它将输出 `Hello World`。 24 | 25 | 第 5 行:`return 0` 结束 `main()` 函数。 26 | 27 | 第 6 行:不要忘记添加右大括号 `}` 以实际结束 `main` 函数。 -------------------------------------------------------------------------------- /docs/c_user_input.md: -------------------------------------------------------------------------------- 1 | C 用户输入 User Input 2 | === 3 | 4 | C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。 5 | 6 | 您已经了解到 `printf()` 用于在 `C` 中输出值。 7 | 8 | 要获取用户输入,您可以使用 `scanf()` 函数 9 | 10 | ## 用户输入 11 | 12 | 输出用户输入的数字 13 | 14 | ```c 15 | #include 16 | int main( ) { 17 | // 创建一个整数变量来存储我们从用户那里得到的数字 18 | int myNum; 19 | 20 | // 要求用户输入一个数字 21 | printf("请输入一个数字: \n"); 22 | 23 | // 获取并保存用户输入的号码 24 | scanf("%d", &myNum); 25 | 26 | // 输出用户输入的数字 27 | printf("您输入的数字: %d", myNum); 28 | } 29 | ``` 30 | 31 | `scanf()` 函数有两个参数:变量的格式说明符(上例中的 `%d`)和引用运算符(`&myNum`),它存储变量的内存地址。 32 | 33 | ## 用户输入字符串 34 | 35 | 您还可以获取用户输入的字符串: 36 | 37 | ```c 38 | #include 39 | int main( ) { 40 | // 创建一个字符串 41 | char firstName[30]; 42 | 43 | // 要求用户输入一些文本 44 | printf("输入您的名字: \n"); 45 | 46 | // 获取并保存文本 47 | scanf("%s", firstName); 48 | 49 | // 输出文本 50 | printf("Hello %s.", firstName); 51 | } 52 | ``` 53 | 54 | 请注意,您必须指定字符串/数组的大小(我们使用了一个非常高的数字,30,但至少我们确定它将为名字存储足够的字符),并且您不必指定引用运算符 (`&`) 在 `scanf()` 中处理字符串时。 -------------------------------------------------------------------------------- /docs/c_variables.md: -------------------------------------------------------------------------------- 1 | C 变量 2 | === 3 | 4 | 变量是存储数据值的容器。 5 | 6 | 在 C 中,有不同类型的变量(用不同的关键字定义),例如: 7 | 8 | - `int` - 存储整数(整数),不带小数,例如 123 或 -123 9 | - `float` - 存储浮点数,带小数,例如 19.99 或 -19.99 10 | - `char` - 存储单个字符,例如“a”或“B”。 字符值用单引号括起来 11 | 12 | ## 声明(创建)变量 13 | 14 | 要创建变量,请指定类型并为其赋值: 15 | 16 | ### 语法 Syntax 17 | 18 | ```c 19 | type variableName = value; 20 | ``` 21 | 22 | 其中 `type` 是 C 类型之一(例如 `int`),`variableName` 是变量的名称(例如 x 或 myName)。 等号用于为变量`赋值`。 23 | 24 | 因此,要创建一个应该存储数字的变量,请查看以下示例: 25 | 26 | ### 示例 1 27 | 28 | 创建一个名为 `myNum` 的 `int` 类型变量并将值 `15` 分配给它: 29 | 30 | ```c 31 | int myNum = 15; 32 | ``` 33 | 34 | ### 示例 2 35 | 36 | 你也可以声明一个变量而不赋值,然后再赋值: 37 | 38 | ```c 39 | int myNum; 40 | myNum = 15; 41 | ``` 42 | 43 | ### 示例 3 44 | 45 | 注意:如果您为现有变量分配新值,它将覆盖以前的值: 46 | 47 | ```c 48 | int myNum = 15; // myNum 值为 15 49 | myNum = 10; // 现在 myNum 值为 10 50 | ``` 51 | 52 | ## 输出变量 53 | 54 | 您从 [输出章节](./c_output.md) 中了解到,您可以使用 `printf()` 函数输出值/打印文本: 55 | 56 | ```c 57 | printf("Hello World!"); 58 | ``` 59 | 60 | 在许多其他编程语言(如 Python、Java 和 C++)中,您通常会使用 **print函数** 显示变量的值。 但是,这在 C 中是不能使用的: 61 | 62 | ```c 63 | int myNum = 15; 64 | printf(myNum); // 没发生什么事 65 | ``` 66 | 67 | 68 | 要在 C 中输出变量,您必须熟悉所谓的“格式说明符”。 69 | 70 | ## 格式说明符 71 | 72 | 格式说明符与 `printf()` 函数一起使用,以告诉编译器变量存储什么类型的数据。 它基本上是变量值的占位符。 73 | 74 | 格式说明符以百分号 `%` 开头,后跟一个字符。 75 | 76 | 例如,要输出 `int` 变量的值,您必须在 `printf()` 函数中使用用双引号括起来的格式说明符 `%d` 或 `%i`: 77 | 78 | ```c 79 | int myNum = 15; 80 | printf("%d", myNum); // 输出 15 81 | ``` 82 | 83 | 要打印其他类型,请使用 `%c` 表示 `char` 和 `%f` 表示 `float`: 84 | 85 | ```c 86 | // 创建变量 87 | int myNum = 5; // 整数 Integer (whole number) 88 | float myFloatNum = 5.99; // 浮点数 Floating point number 89 | char myLetter = 'D'; // 字符串 Character 90 | 91 | // 打印变量 92 | printf("%d\n", myNum); 93 | printf("%f\n", myFloatNum); 94 | printf("%c\n", myLetter); 95 | ``` 96 | 97 | 要组合文本和变量,请在 `printf()` 函数中用逗号分隔它们: 98 | 99 | ```c 100 | int myNum = 6; 101 | printf("我最喜欢的号码是: %d", myNum); 102 | ``` 103 | 104 | 要在单个 `printf()` 函数中打印不同的类型,可以使用以下命令: 105 | 106 | ```c 107 | int myNum = 5; 108 | char myLetter = 'D'; 109 | printf("My number is %d and my letter is %c", myNum, myLetter); 110 | ``` 111 | 112 | 您将了解有关 [下一章中的数据类型](./c_data_types.md) 的更多信息。 113 | 114 | ## 添加变量相加 115 | 116 | 要将变量添加到另一个变量,可以使用 `+` 运算符: 117 | 118 | ```c 119 | int x = 5; 120 | int y = 6; 121 | int sum = x + y; 122 | printf("%d", sum); 123 | ``` 124 | 125 | ## 声明多个变量 126 | 127 | 要声明多个相同类型的变量,请使用**逗号分隔**列表: 128 | 129 | ```c 130 | int x = 5, y = 6, z = 50; 131 | printf("%d", x + y + z); 132 | ``` 133 | 134 | 您还可以将**相同的值**分配给相同类型的多个变量: 135 | 136 | ```c 137 | int x, y, z; 138 | x = y = z = 50; 139 | printf("%d", x + y + z); 140 | ``` 141 | 142 | ## C 变量名称 143 | 144 | 所有 C **变量**必须用**唯一名称** **标识**。 145 | 146 | 这些唯一名称称为**标识符**。 147 | 148 | 标识符可以是短名称(如 x 和 y)或更具描述性的名称(age、sum、totalVolume)。 149 | 150 | **注意:** 建议使用描述性名称以创建可理解和可维护的代码: 151 | 152 | ```c 153 | // 👍 Good 154 | int minutesPerHour = 60; 155 | // 👎 正确的,但并不那么容易理解 `m` 实际上是什么 156 | int m = 60; 157 | ``` 158 | 159 | 命名变量的 **一般规则** 是: 160 | 161 | * 名称可以包含字母、数字和下划线 162 | * 名称必须以字母或下划线 (\_) 开头 163 | * 名称区分大小写(`myVar` 和 `myvar` 是不同的变量) 164 | * 名称不能包含空格或特殊字符,如 `!`、`#`、`%` 等。 165 | * 保留字(如`int`)不能用作名称 166 | 167 | -------------------------------------------------------------------------------- /docs/c_while_loop.md: -------------------------------------------------------------------------------- 1 | C While 循环 2 | === 3 | 4 | ## 循环 5 | 6 | 只要达到指定的条件,循环就可以执行一段代码。 7 | 8 | 循环很方便,因为它们可以节省时间、减少错误并且使代码更具可读性。 9 | 10 | ## While 循环 11 | 12 | 只要指定条件为 `true`,`while` 循环就会遍历代码块: 13 | 14 | ### 语法 15 | 16 | ```c 17 | while (条件) { 18 | // 要执行的代码块 19 | } 20 | ``` 21 | 22 | 在下面的示例中,只要变量 (`i`) 小于 `5`,循环中的代码就会一遍又一遍地运行: 23 | 24 | ```c 25 | int i = 0; 26 | 27 | while (i < 5) { 28 | printf("%d\n", i); 29 | i++; 30 | } 31 | ``` 32 | 33 | **注意:** 不要忘记增加条件中使用的变量(`i++`),否则循环永远不会结束,成为“死循环”! 34 | 35 | ## Do/While 循环 36 | 37 | `do/while` 循环是 `while` 循环的变体。 该循环将执行一次代码块,在检查条件是否为真之前,只要条件为真,它将重复循环。 38 | 39 | ### 语法 40 | 41 | ```c 42 | do { 43 | // 要执行的代码块 44 | } while (条件); 45 | ``` 46 | 47 | 下面的示例使用 `do/while` 循环。 循环将始终至少执行一次,即使条件为假,因为代码块在条件测试之前执行: 48 | 49 | ```c 50 | int i = 0; 51 | 52 | do { 53 | printf("%d\n", i); 54 | i++; 55 | } while (i < 5); 56 | ``` 57 | 58 | **注意:** 不要忘记增加条件中使用的变量,否则循环永远不会结束,成为“死循环”! 59 | 60 | ## 另外一个示例 61 | 62 | ```c 63 | #include 64 | int main(){ 65 | int n=0; 66 | printf("Input a string:"); 67 | while(getchar()!='\n') n++; 68 | printf("字符数: %d\n", n); 69 | return 0; 70 | } 71 | ``` 72 | 73 | 运行结果: 74 | 75 | ```bash 76 | 输入一个字符串:c tutorial ↙ 77 | 字符数: 15 78 | ``` 79 | 80 | 程序中的循环条件为 `getchar()!='\n'`,其意义是,只要从键盘输入的字符不是回车就继续循环。循环体 `n++;` 完成对输入字符个数计数。 -------------------------------------------------------------------------------- /example/calculations_with_cookies.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int cookies = 5; // 饼干总数 6 | int cookie_calories = 125; // 每卡路里需要的饼干 7 | int total_eaten = 0; // 吃饼干总数 8 | 9 | int eaten = 2; // 要吃的数量 10 | cookies = cookies - eaten; // 减去吃掉饼干,获取剩下的饼干 11 | total_eaten = total_eaten + eaten; 12 | printf("\n我吃了 %d 个饼干。 剩下 %d 个饼干。", eaten, cookies); 13 | 14 | eaten = 3; // 吃掉饼干的新值,重新赋值 15 | cookies = cookies - eaten; // 减去吃掉饼干,获取剩下的饼干 16 | total_eaten = total_eaten + eaten; 17 | printf("\n我又吃了 %d 个。 现在剩下 %d 个饼干。\n", eaten, cookies); 18 | printf("\n消耗的总能量为 %d 卡路里。\n", total_eaten * cookie_calories); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /example/division_with_float_values.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | float plank_length = 10.0f; // 长度 6 | float piece_count = 4.0f; // 多少块 7 | float piece_length = 0.0f; // 每块的长度 8 | 9 | piece_length = plank_length / piece_count; 10 | printf("一块 %f 英尺长的木板可以切成 %f 块 %f 英尺长。\n", plank_length, piece_count, piece_length); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /example/hello.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Written byu Kenny Wong 3 | * Copyright 2019 4 | */ 5 | 6 | #include 7 | 8 | // 每个程序总是从 main 这个函数开始执行 9 | int main() 10 | { 11 | printf("Hello world!"); // 这里是单行注释输出日志 12 | return 0; // main 函数 返回了个 0,表示正常终止程序,非 0 表示异常 13 | } -------------------------------------------------------------------------------- /example/simple_calculations.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int total_pets; 6 | int cats; 7 | int dogs; 8 | int ponies; 9 | int others; 10 | 11 | // 设置每种宠物的数量 12 | cats = 2; 13 | dogs = 1; 14 | ponies = 1; 15 | others = 46; 16 | 17 | // 计算宠物总数 18 | total_pets = cats + dogs + ponies + others; 19 | 20 | printf("我们共有 %d 只宠物!\n", total_pets); // 输出结果 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /example/using_a_variable.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int salary; // 声明一个名为 salary 的变量 6 | salary = 10000; // 将 10000 存储在 salary 中 7 | printf("My salary is %d.\n", salary); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /example/using_more_variables.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int brothers; // 声明一个名为 brothers 的变量 6 | int brides; // 和一个叫做 brides 的变量 7 | 8 | brothers = 7; // 将 7 存储在变量 brothers 中 9 | brides = 7; // 将 7 存储在变量 brides 中 10 | 11 | // 输出变量内容 12 | printf("%d brides for %d brothers\n", brides, brothers); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /idoc.chapters.yml: -------------------------------------------------------------------------------- 1 | 2 | ## C Tutorial 3 | 4 | - /: Tutorial 5 | - c_getstarted.md: C 开始 Get Started 6 | - c_syntax.md: C 语法 Syntax 7 | - c_output.md: C 输出(打印文本) Output 8 | - c_comments.md: C 注释 Comments 9 | - c_variables.md: C 变量 Variables 10 | - c_data_types.md: C 数据类型 Data Types 11 | - c_constants.md: C 常量 Constants 12 | - c_operators.md: C 运算符 Operators 13 | - c_conditions.md: C If...Else 14 | - c_switch.md: C Switch 15 | - c_while_loop.md: C While 循环 16 | - c_for_loop.md: C For 循环 17 | - c_break_continue.md: C 跳出循环 Break/Continue 18 | - c_arrays.md: C 数组 Arrays 19 | - c_enum.md: C 枚举 Enum 20 | - c_strings.md: C 字符串 Strings 21 | - c_user_input.md: C 用户输入 User Input 22 | - c_memory_address.md: C 内存地址 Memory Address 23 | - c_pointers.md: C 指针 Pointers 24 | - c_preprocessors.md: C 预处理器 25 | 26 | ## C Functions 27 | 28 | - /: 函数 29 | - c_functions.md: C 函数 Functions 30 | - c_functions_parameters.md: C 函数参数 31 | - c_functions_decl.md: C 函数声明 32 | - c_functions_recursion.md: C 递归 33 | - c_math.md: C 数学函数 34 | 35 | ## C Structures 36 | 37 | - /: 结构 38 | - c_structs.md: C 结构 Structures 39 | 40 | - /: 文件处理 41 | - c_file_io.md: C 文件处理 42 | 43 | - /: 参考 44 | - c_keywords.md: C 关键字 Keywords 45 | 46 | -------------------------------------------------------------------------------- /idoc.yml: -------------------------------------------------------------------------------- 1 | site: 'C Tutorial' 2 | logo: ./logo.svg 3 | favicon: ./logo.svg 4 | 5 | cacheFileStat: true 6 | homepage: https://wangchujiang.com/c-tutorial/ 7 | 8 | menus: 9 | 首页: index.html 10 | 官方文档: 11 | url: https://zh.cppreference.com/w/c 12 | target: __blank 13 | 赞助: https://jaywcjlove.github.io/#/sponsor 14 | 15 | editButton: 16 | label: GitHub 上编辑此页 17 | url: https://github.com/jaywcjlove/c-tutorial/blob/master/ 18 | 19 | footer: | 20 | Released under the MIT License. Copyright © 2022 Kenny Wong
21 | Generated by idoc v{{idocVersion}} -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "c-tutorial", 3 | "version": "1.0.3", 4 | "description": "C 语言入门学习", 5 | "scripts": { 6 | "start": "idoc --watch", 7 | "build": "idoc" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jaywcjlove/c-tutorial.git" 12 | }, 13 | "keywords": [], 14 | "devDependencies": { 15 | "idoc": "^1.26.6" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "packageRules": [ 6 | { 7 | "matchPackagePatterns": ["*"], 8 | "rangeStrategy": "replace" 9 | } 10 | ] 11 | } 12 | --------------------------------------------------------------------------------