From 7db43897083d851bddf089ae251d6f095309e157 Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Thu, 13 Oct 2022 01:19:47 +0800 Subject: [PATCH] feat: add `c.md` cheatsheet. --- README.md | 1 + docs/c.md | 806 +++++++++++++++++++++++++++++++++++++++++++ scripts/assets/c.svg | 3 + scripts/style.css | 11 +- 4 files changed, 820 insertions(+), 1 deletion(-) create mode 100644 docs/c.md create mode 100644 scripts/assets/c.svg diff --git a/README.md b/README.md index bea720b..0fe4920 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Quick Reference ## 编程 [Bash](./docs/bash.md) +[C](./docs/c.md) [Docker](./docs/docker.md) [Dockerfile](./docs/dockerfile.md) [Electron](./docs/electron.md) diff --git a/docs/c.md b/docs/c.md new file mode 100644 index 0000000..4d6b8fd --- /dev/null +++ b/docs/c.md @@ -0,0 +1,806 @@ +C 备忘清单 +=== + +提供基本语法和方法的 C 快速参考备忘单。 + +入门 +---- + +### hello.c + + +```c +#include + +int main() { + printf("Hello World!"); + return 0; +} +``` + +使用 `gcc` 编译 `hello.c` 文件 + +```bash +$ gcc -o hello hello.c +``` + +运行编译后的二进制文件(`hello`) + +```bash +$ ./hello +# 输出 => Hello World +``` + +### 变量 + + +```c +int myNum = 15; + +int myNum2; // 不赋值,然后再赋值 +myNum2 = 15; + +int myNum3 = 15; // myNum3 值为 15 +myNum3 = 10; // 现在 myNum3 值为 10 + +float myFloatNum = 5.99; // 浮点数 +char myLetter = 'D'; // 字符串 + +int x = 5; +int y = 6; +int sum = x + y; // 添加变量相加 +// 声明多个变量 +int x = 5, y = 6, z = 50; +``` + +### 常量 Constants + +```c +const int minutesPerHour = 60; +const float PI = 3.14; +``` + +最佳实践 + +```c +const int BIRTHYEAR = 1980; +``` + +### 注释 + +```c +// 这是一个注释 +printf("Hello World!"); // 这是一个注释 +/* 多行注释,上面的代码将打印出 Hello World! +到屏幕上,真是太棒了 */ +``` + +### 打印文本 + +```c +printf("I am learning C."); +int testInteger = 5; +printf("Number = %d", testInteger); + +float f = 5.99; // 浮点数 +printf("Value = %f", f); + +short a = 0b1010110; // 2 进制数字 +int b = 02713; // 8 进制数字 +long c = 0X1DAB83; // 16 进制数字 + +// 以 8 进制形似输出 +printf("a=%ho, b=%o, c=%lo\n", a, b, c); +// 输出 => a=126, b=2713, c=7325603 + +// 以 10 进制形式输出 +printf("a=%hd, b=%d, c=%ld\n", a, b, c); +// 输出 => a=86, b=1483, c=1944451 + +// 以 16 进制形式输出(字母小写) +printf("a=%hx, b=%x, c=%lx\n", a, b, c); +// 输出 => a=56, b=5cb, c=1dab83 + +// 以 16 进制形式输出(字母大写) +printf("a=%hX, b=%X, c=%lX\n", a, b, c); +// 输出 => a=56, b=5CB, c=1DAB83 +``` + +### 控制空格数 + +```c +int a1=20, a2=345, a3=700; +int b1=56720, b2=9999, b3=20098; +int c1=233, c2=205, c3=1; +int d1=34, d2=0, d3=23; + +printf("%-9d %-9d %-9d\n", a1, a2, a3); +printf("%-9d %-9d %-9d\n", b1, b2, b3); +printf("%-9d %-9d %-9d\n", c1, c2, c3); +printf("%-9d %-9d %-9d\n", d1, d2, d3); +``` + +输出结果 + +```bash +20 345 700 +56720 9999 20098 +233 205 1 +34 0 23 +``` + +`%-9d` 中,`d` 表示以 `10` 进制输出,`9` 表示最少占 `9` 个字符的宽度,宽度不足以空格补齐,`-` 表示左对齐 + +### 字符串 Strings + +```c +char greetings[] = "Hello World!"; +printf("%s", greetings); +``` + +访问字符串 + +```c +char greetings[] = "Hello World!"; +printf("%c", greetings[0]); +``` + +修改字符串 + +```c +char greetings[] = "Hello World!"; +greetings[0] = 'J'; + +printf("%s", greetings); +// 输出 "Jello World!" +``` + +另一种创建字符串的方法 + +```c +char greetings[] = {'H','e','l','l','\0'}; + +printf("%s", greetings); +// 输出 "Hell!" +``` + +`C` **没有** String 类型,使用 `char` 类型并创建一个字符 `array` + +### 条件判断 + + +```c +int time = 20; +if (time < 18) { + printf("再会!"); +} else { + printf("晚上好!"); +} +// 输出 -> "晚上好!" +int time = 22; +if (time < 10) { + printf("早上好!"); +} else if (time < 20) { + printf("再会!"); +} else { + printf("晚上好!"); +} +// 输出 -> "晚上好!" +``` + +### 三元运算符 + + +```c +int time = 20; +(time < 18) ? printf("再会!") : printf("晚上好!"); +``` + +### Switch + +```c +int day = 4; + +switch (day) { + case 3: printf("周三"); break; + case 4: printf("周四"); break; + default: + printf("期待周末"); +} +// 输出 -> "周四" (day 4) +``` + +### While 循环 + +```c +int i = 0; + +while (i < 5) { + printf("%d\n", i); + i++; +} +``` + +**注意**:不要忘记增加条件中使用的变量,否则循环永远不会结束,成为“死循环”! + +### Do/While 循环 + +```c +int i = 0; + +do { + printf("%d\n", i); + i++; +} while (i < 5); +``` + +### For 循环 + +```c +int i; + +for (i = 0; i < 5; i++) { + printf("%d\n", i); +} +``` + +### 跳出循环 Break/Continue + + +```c +int i; + +for (i = 0; i < 10; i++) { + if (i == 4) { + break; + } + printf("%d\n", i); +} +``` + +在 `i` 等于 `4` 时跳出循环 + +```c +int i; + +for (i = 0; i < 10; i++) { + if (i == 4) { + continue; + } + printf("%d\n", i); +} +``` + +示例跳过 `4` 的值 + +### While Break 示例 + +```c +int i = 0; + +while (i < 10) { + if (i == 4) { + break; + } + printf("%d\n", i); + i++; +} +``` + +### While continue 示例 + +```c +int i = 0; + +while (i < 10) { + i++; + if (i == 4) { + continue; + } + printf("%d\n", i); +} +``` + +### 数组 Arrays + + +```c +int myNumbers[] = {25, 50, 75, 100}; +printf("%d", myNumbers[0]); +// 输出 25 +``` + +更改数组元素 + +```c +int myNumbers[] = {25, 50, 75, 100}; +myNumbers[0] = 33; + +printf("%d", myNumbers[0]); +``` + +循环遍历数组 + +```c +int myNumbers[] = {25, 50, 75, 100}; +int i; + +for (i = 0; i < 4; i++) { + printf("%d\n", myNumbers[i]); +} +``` + +设置数组大小 + +```c +// 声明一个由四个整数组成的数组: +int myNumbers[4]; +// 添加元素 +myNumbers[0] = 25; +myNumbers[1] = 50; +myNumbers[2] = 75; +myNumbers[3] = 100; +``` + +### 枚举 Enum + + +```c +enum week { Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun }; +``` + +定义枚举变量 + +```c +enum week a, b, c; + +enum week { Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c; +``` + +有了枚举变量,就可以把列表中的值赋给它 + +```c +enum week { Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun }; +enum week a = Mon, b = Wed, c = Sat; +// 或者 +enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat; +``` + +### 枚举示例应用 + +```c +enum week {Mon = 1, Tues, Wed, Thurs} day; + +scanf("%d", &day); + +switch(day){ + case Mon: puts("Monday"); break; + case Tues: puts("Tuesday"); break; + case Wed: puts("Wednesday"); break; + case Thurs: puts("Thursday"); break; + default: puts("Error!"); +} +``` + +### 用户输入 + +```c +// 创建一个整数变量来存储我们从用户那里得到的数字 +int myNum; + +// 要求用户输入一个数字 +printf("请输入一个数字: \n"); + +// 获取并保存用户输入的号码 +scanf("%d", &myNum); + +// 输出用户输入的数字 +printf("您输入的数字: %d", myNum); +``` + +### 用户输入字符串 + +```c +// 创建一个字符串 +char firstName[30]; +// 要求用户输入一些文本 +printf("输入您的名字: \n"); +// 获取并保存文本 +scanf("%s", firstName); +// 输出文本 +printf("Hello %s.", firstName); +``` + +### 内存地址 + +创建变量时,会为该变量分配一个内存地址 + +```c +int myAge = 43; + +printf("%p", &myAge); +// 输出:0x7ffe5367e044 +``` + +要访问它,请使用引用运算符 (`&`) + +### 创建指针 + +```c +int myAge = 43; // 一个 int 变量 +printf("%d", myAge); // 输出 myAge(43)的值 + +// 输出 myAge 的内存地址(0x7ffe5367e044) +printf("%p", &myAge); +``` + +### 指针变量 + + +```c +int myAge = 43; // 一个 int 变量 +int* ptr = &myAge; // 名为 ptr 的指针变量,用于存储 myAge 的地址 + +printf("%d\n", myAge); // 输出 myAge (43) 的值 + +printf("%p\n", \&myAge); // 输出 myAge 的内存地址(0x7ffe5367e044) + +printf("%p\n", ptr); // 用指针(0x7ffe5367e044)输出myAge的内存地址 +``` + +### 取消引用 + +```c +int myAge = 43; // 变量声明 +int* ptr = &myAge; // 指针声明 + +// 参考:用指针输出 myAge 的 +// 内存地址(0x7ffe5367e044) +printf("%p\n", ptr); +// 取消引用:用指针输出 myAge 的值 (43) +printf("%d\n", *ptr); +``` + +运算符 +--- + +### 算术运算符 + +```c +int myNum = 100 + 50; +int sum1 = 100 + 50; // 150 (100 + 50) +int sum2 = sum1 + 250; // 400 (150 + 250) +int sum3 = sum2 + sum2; // 800 (400 + 400) +``` + +---- + +| Operator | Name | Description | Example | +| -------- | -------- | -------- | -------- | +| `+` | 加 | 将两个值相加 | `x + y` | +| `-` | 减 | 从另一个值中减去一个值 | `x - y` | +| `*` | 乘 | 将两个值相乘 | `x * y` | +| `/` | 除 | 将一个值除以另一个 | `x / y` | +| `%` | 取模 | 返回除法余数 | `x % y` | +| `++` | 增量 | 将变量的值增加 1 | `++` | +| `--` | 乘量 | 将变量的值减 1 | `--x` | + +### 赋值运算符 + +| 符号 | 示例 | 如同 | +| -------- | ------- | ---------- | +| `=` | x `=` 5 | x `=` 5 | +| `+=` | x `+=` 3 | x `=` x `+` 3 | +| `-=` | x `-=` 3 | x `=` x `-` 3 | +| `*=` | x `*=` 3 | x `=` x `*` 3 | +| `/=` | x `/=` 3 | x `=` x `/` 3 | +| `%=` | x `%=` 3 | x `=` x `%` 3 | +| `&=` | x `&=` 3 | x `=` x `&` 3 | +| `\|=` | x `\|=` 3 | x `=` x `\|` 3 | +| `^=` | x `^=` 3 | x `=` x `^` 3 | +| `>>=` | x `>>=` 3 | x `=` x `>>` 3 | +| `<<=` | x `<<=` 3 | x `=` x `<<` 3 | + +### 比较运算符 + +```c +int x = 5; +int y = 3; + +printf("%d", x > y); +// 返回 1(真),因为 5 大于 3 +``` + +---- + +| 符号 | 名称 | 示例 | +| -------- | ------- | ------- | +| `==` | 等于 | x `==` y | +| `!=` | 不等于 | x `!=` y | +| `>` | 大于 | x `>` y | +| `<` | 小于 | x `<` y | +| `>=` | 大于或等于 | x `>=` y | +| `<=` | 小于或等于 | x `<=` y | + +比较运算符用于比较两个值 + +### 逻辑运算符 + + +| 符号 | 名称 | 说明 | 示例 | +| -------- | -------- | -------- | -------- | +| `&&` | `与`逻辑 | 如果两个语句都为真,则返回真 | `x < 5 && x < 10` | +| `\|\|` | `或`逻辑 | 如果其中一个语句为真,则返回真 | `x < 5 \|\| x < 4` | +| `!` | `非`逻辑 | 反转结果,如果结果为真则返回假 | `!(x < 5 && x < 10)` | + +### 运算符示例 + + +```c +unsigned int a = 60; /* 60 = 0011 1100 */ +unsigned int b = 13; /* 13 = 0000 1101 */ +int c = 0; + +c = a & b; /* 12 = 0000 1100 */ +printf("Line 1 - c 的值是 %d\n", c ); + +c = a | b; /* 61 = 0011 1101 */ +printf("Line 2 - c 的值是 %d\n", c ); +c = a ^ b; /* 49 = 0011 0001 */ +printf("Line 3 - c 的值是 %d\n", c ); +c = ~a; /*-61 = 1100 0011 */ +printf("Line 4 - c 的值是 %d\n", c ); +c = a << 2; /* 240 = 1111 0000 */ +printf("Line 5 - c 的值是 %d\n", c ); +c = a >> 2; /* 15 = 0000 1111 */ +printf("Line 6 - c 的值是 %d\n", c ); +``` + +### 位运算符 + + +运算符 | 描述 | 实例 +:- |:- |:- +`&` | 按位与操作,按二进制位进行"与"运算 | `(A & B)` 将得到 `12` 即为 0000 1100 +`\|` | 按位或运算符,按二进制位进行"或"运算 | `(A \| B)` 将得到 `61` 即为 0011 1101 +`^` | 异或运算符,按二进制位进行"异或"运算 | `(A ^ B)` 将得到 `49` 即为 0011 0001 +`~` | 取反运算符,按二进制位进行"取反"运算 | `(~A)` 将得到 `-61` 即为 1100 0011 +`<<` | 二进制左移运算符 | `A << 2` 将得到 `240` 即为 1111 0000 +`>>` | 二进制右移运算符 | `A >> 2` 将得到 `15` 即为 0000 1111 + +数据类型 Data Types +--- + +### 基本数据类型 + + +| 数据类型 | 大小 Size | 范围 Range | 描述 Description | +| ----- | ----- | ----- | ----- | +| `char` | 1 字节 | `−128` ~ `127` | 单个字符/字母/数字/ASCII | +| `signed char` | 1 字节 | `−128` ~ `127` | - | +| `unsigned char` | 1 字节 | `0` ~ `255` | - | +| `int` | `2` 到 `4` 字节 | `−32,768` ~ `32,767` | 存储整数 | +| `signed int` | 2 字节 | `−32,768` ~ `32,767` | | +| `unsigned int` | 2 字节 | `0` ~ `65,535` | | +| `short int` | 2 字节 | `−32,768` ~ `32,767` | | +| `signed short int` | 2 字节 | `−32,768` ~ `32,767` | | +| `unsigned short int` | 2 字节 | `0` ~ `65,535` | | +| `long int` | 4 字节 | `-2,147,483,648` ~ `2,147,483,647` | | +| `signed long int` | 4 字节 | `-2,147,483,648` ~ `2,147,483,647` | | +| `unsigned long int` | 4 字节 | `0` ~ `4,294,967,295` | | +| `float` | 4 字节 | | | +| `double` | 8 字节 | | | +| `long double` | 10 字节 | | | + +### 数据类型 + +```c +// 创建变量 +int myNum = 5; // 整数 +float myFloatNum = 5.99; // 浮点数 +char myLetter = 'D'; // 字符串 +// 高精度浮点数据或数字 +double myDouble = 3.2325467; +// 打印输出变量 +printf("%d\n", myNum); +printf("%f\n", myFloatNum); +printf("%c\n", myLetter); +printf("%lf\n", myDouble); +``` + +--- + +数据类型 | 说 明 +:- | :- +`char` | 字符型 +`short` | 短整型 +`int` | 整型 +`long` | 长整型 +`float` | 单精度浮点型 +`double` | 双精度浮点型 +`void` | 无类型 + + +### 基本格式说明符 + +| 格式说明符 | 数据类型 | +| ----- | ----- | +| `%d` 或 `%i` | `int` 整数 | +| `%f` | `float` 单精度的十进制类型 | +| `%lf` | `double` 高精度浮点数据或数字 | +| `%c` | `char` 字符 | +| `%s` | 用于 `strings` 字符串 | + +### 基本格式说明符 + +| | short | int | long | +| ---- | ---- | ---- | ---- | +| 8 进制 | `%ho` | `%o` | `%lo` | +| 10 进制 | `%hd` | `%d` | `%ld` | +| 16 进制 | `%hx` / `%hX` | `%x` / `%X` | `%lx` / `%lX` | + +### 数据格式示例 + +```c +int myNum = 5; +float myFloatNum = 5.99; // 浮点数 +char myLetter = 'D'; // 字符串 +// 打印输出变量 +printf("%d\n", myNum); +printf("%f\n", myFloatNum); +printf("%c\n", myLetter); +``` + +预处理器 +--- + +### 预处理器指令 + + +指令 | 描述 +---- | ---- +`#define` | 定义宏 +`#include` | 包含一个源代码文件 +`#undef` | 取消已定义的宏 +`#ifdef` | 如果宏已经定义,则返回真 +`#ifndef` | 如果宏没有定义,则返回真 +`#if` | 如果给定条件为真,则编译下面代码 +`#else` | `#if` 的替代方案 +`#elif` | 如果 `#if` 条件为假,当前条件为`真` +`#endif` | 结束一个 `#if……#else` 条件编译块 +`#error` | 当遇到标准错误时,输出错误消息 +`#pragma` | 使用标准化方法,向编译器发布特殊的命令到编译器中 + +```c +// 所有的 MAX_ARRAY_LENGTH 替换为 20 +#define MAX_ARRAY_LENGTH 20 +// 系统库中获取 stdio.h +#include +// 本地目录中获取 myheader.h +#include "myheader.h" +#undef FILE_SIZE +#define FILE_SIZE 42 // 取消已定义并定义为 42 +``` + +### 预定义宏 + + +宏 | 描述 +---- | ---- +`__DATE__` | 当前日期,一个以 "MMM DD YYYY" 格式表示的字符常量 +`__TIME__` | 当前时间,一个以 "HH:MM:SS" 格式表示的字符常量 +`__FILE__` | 这会包含当前文件名,一个字符串常量 +`__LINE__` | 这会包含当前行号,一个十进制常量 +`__STDC__` | 当编译器以 `ANSI` 标准编译时,则定义为 `1` + + +`ANSI C` 定义了许多宏,您可以使用这些宏,但是不能直接修改这些预定义的宏 + +#### 预定义宏示例 + +```c +#include + +int main() { + printf("File :%s\n", __FILE__); + printf("Date :%s\n", __DATE__); + printf("Time :%s\n", __TIME__); + printf("Line :%d\n", __LINE__); + printf("ANSI :%d\n", __STDC__); +} +``` + +### 宏延续运算符(\) + +一个宏通常写在一个单行上。 + +```c +#define message_for(a, b) \ + printf(#a " 和 " #b ": 我们爱你!\n") +``` + +如果宏太长,一个单行容纳不下,则使用宏延续运算符 `\` + +### 字符串常量化运算符(#) + +```c +#include + +#define message_for(a, b) \ + printf(#a " 和 " #b ": 我们爱你!\n") + +int main(void) { + message_for(Carole, Debra); + return 0; +} +``` + +当上面的代码被编译和执行时,它会产生下列结果: + +``` +Carole 和 Debra: 我们爱你! +``` + +需要把一个宏的参数转换为字符串常量时,使用字符串常量化运算符 `#` + + + +### 标记粘贴运算符(##) + +```c +#include + +#define tokenpaster(n) printf ("token" #n " = %d", token##n) + +int main(void){ + int token34 = 40; + tokenpaster(34); + return 0; +} +``` + +### defined() 运算符 + +```c +#include + +#if !defined (MESSAGE) + #define MESSAGE "You wish!" +#endif + +int main(void) { + printf("Here is the message: %s\n", MESSAGE); + return 0; +} +``` + +### 参数化的宏 + +```c +int square(int x) { + return x * x; +} +``` + +宏重写上面的代码,如下: + +```c +#define square(x) ((x) * (x)) +``` + +宏名称和左圆括号之间不允许有空格 + +```c +#include +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +int main(void) { + printf("Max between 20 and 10 is %d\n", MAX(10, 20)); + return 0; +} +``` + +另见 +--- + +- [C 教程](https://jaywcjlove.github.io/c-tutorial) _(jaywcjlove.github.io)_ \ No newline at end of file diff --git a/scripts/assets/c.svg b/scripts/assets/c.svg new file mode 100644 index 0000000..7975e35 --- /dev/null +++ b/scripts/assets/c.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/scripts/style.css b/scripts/style.css index f5861d6..3a2e664 100644 --- a/scripts/style.css +++ b/scripts/style.css @@ -465,11 +465,20 @@ a.text-grey { color: rgb(148 163 184/1); } -body:not(.home) .h2wrap > h2 a::after { +body:not(.home) .h2wrap > h2 a::after, body:not(.home) .h3wrap > h3 a::after { content: '#'; padding-right: 0.5rem; color: rgb(16 185 129/1); } +body:not(.home) .h3wrap > h3 a::after { + position: absolute; + left: -18px; + font-size: 1rem; + display: none; +} +body:not(.home) .h3wrap > h3:hover a::after { + display: initial; +} .wrap-header.h3wrap { z-index: 0;