From 6c8217202a4417b793b3e17aca68199d270565dc Mon Sep 17 00:00:00 2001 From: Thanatos <574401159@qq.com> Date: Mon, 30 Dec 2024 03:01:44 +0800 Subject: [PATCH] doc: update c.md (#911) --- docs/c.md | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/docs/c.md b/docs/c.md index f92050275b4..484b94fa392 100644 --- a/docs/c.md +++ b/docs/c.md @@ -54,11 +54,21 @@ int y = 6; int sum = x + y; // 添加变量相加 // 声明多个变量 int x = 5, y = 6, z = 50; +int a, b, c = 10; + +//仅声明变量不初始化 +int result; +// 如果未初始化,变量的值是未定义的,使用它会导致错误的结果。 +// 此时,变量的值是随机的,因此在使用该变量之前必须进行初始化。 +result = result + 10; // 错误:未初始化的变量 result 会导致不可预测的结果 + +// 部分编译器会输出 Warning,警告未初始化的变量可能导致未定义行为。 + ``` ### 常量 Constants -常量在 C 语言中我们一般理解为不能被改变的值,活用常量与符号常量 +常量在 C 语言中我们一般理解为不能被改变的值,活用常量与符号常量,可以使代码更加清晰和安全 ```c const int minutesPerHour = 60; @@ -71,13 +81,36 @@ const float PI = 3.14; const int BIRTHYEAR = 1980; ``` +说明与补充: +1. **常量命名规范**:常量通常使用全大写字母,多个单词之间用下划线分隔(例如 BIRTHYEAR、MAX_LENGTH)。 + +2. **`#define` 与 `const`**: + - **`#define`**:宏常量通常在预处理阶段进行替换,不进行类型检查; + - **`const`**:类型安全的常量,编译器可以检查类型,一般更推荐使用 `const` + +3. **数组大小**:可以使用 `const` 来定义数组的常量大小,这样编译器会将其作为编译时常量处理 + + + ### 注释 ```c // 这是一个注释 printf("Hello World!"); // 这是一个注释 -/* 多行注释,上面的代码将打印出 Hello World! -到屏幕上,真是太棒了 */ +/* + 多行注释:用于注释跨多行的内容 + 上面的代码将打印出 Hello World! 到屏幕上 + 注意:多行注释不能嵌套,否则会导致编译错误 +*/ +``` +**注意**: +单行注释`//`可以嵌套,`////////这种注释也是对的` +但行内注释应避免过长,以免影响代码可读性 + +多行注释不能嵌套,否则会导致编译错误(详见下文 [### Warning 和 Error](#warning-和-error) ) +```c +/* 这是一个多行注释的开始 + /* 这是嵌套的多行注释,C语言不支持 */ ``` ### 打印文本 @@ -93,8 +126,9 @@ printf("Value = %f", f); short a = 0b1010110; // 2 进制数字 int b = 02713; // 8 进制数字 long c = 0X1DAB83; // 16 进制数字 +//变量a和c分别为short和long型,所以输出必须加上对应的修饰符h和l -// 以 8 进制形似输出 +// 以 8 进制形式输出 printf("a=%ho, b=%o, c=%lo\n", a, b, c); // 输出 => a=126, b=2713, c=7325603 @@ -119,6 +153,7 @@ int b1=56720, b2=9999, b3=20098; int c1=233, c2=205, c3=1; int d1=34, d2=0, d3=23; +// %-9d: 十进制输出,最少宽度为9,左对齐 printf("%-9d %-9d %-9d\n", a1, a2, a3); printf("%-9d %-9d %-9d\n", b1, b2, b3); printf("%-9d %-9d %-9d\n", c1, c2, c3); @@ -134,7 +169,29 @@ printf("%-9d %-9d %-9d\n", d1, d2, d3); 34 0 23 ``` -`%-9d` 中,`d` 表示以 `10` 进制输出,`9` 表示最少占 `9` 个字符的宽度,宽度不足以空格补齐,`-` 表示左对齐 +`%-9d` 中,`d` 表示以 `10` 进制输出,`9` 表示最少占 `9` 个字符的宽度,宽度不足以空格补齐,`-` 表示左对齐,如果不使用左对齐则默认右对齐 + +对于整型数据,假设: +```c +int a = 12345; +printf(“%md”,a); +``` +1. 若 m <= 实际数据的宽度,则按实际情况输出 +2. 若 m > 实际数据的宽度,则在实际数据的左边用空格补齐 +3. `printf(“%0md”,a);` 则实际的结果不够 m 位的在数据的左边用0补齐 + +对于浮点型数据,宽度=整数部分的位数+小数点+小数部分的宽度 +假设: +```c +float a = 1.2345; +printf(“%m.nf”,a); //m --整个数据的宽度,n--小数位数 +``` +1. 实际小数位数>n,截去小数右边多余的小数,截去的第一位要注意四舍五入 +2. 实际小数位数< n,在小数的最后补0 +3. 若m省略则写作%.n ,整数部分按照实际输出,小数部分按照以上两个规则进行 +4. m < n+1,自动突破宽度为m的限制,按照实际数据进行输出 +5. m > n+1,整个数据的最左边补空格 + ### 字符串 Strings @@ -191,14 +248,37 @@ if (time < 10) { printf("晚上好!"); } // 输出 -> "晚上好!" + +int time = 10; +if (time > 8) { + //再嵌套一个if + if (time < 12) { + printf("中午好!") + } +} +// 输出 -> "中午好!" ``` ### 三元运算符 +三元运算符(? :)是一种简洁的条件判断方式,常用于根据条件选择表达式的值,由三个部分组成: +- 一个条件表达式 +- 条件为真时的结果 +- 条件为假时的结果 +基本语法:`(condition) ? expression1 : expression2;` +如果`condition`为真,则返回`expression1`否则返回`expression2`。 ```c int time = 20; (time < 18) ? printf("再会!") : printf("晚上好!"); +// 输出 -> "晚上好!" +``` + +三元运算符可以嵌套使用,但嵌套层级太多会导致代码可读性下降,不建议在实际场景使用 +```c +int time = 22; +printf((time < 10) ? "早上好!" : (time < 20) ? "再会!" : "晚上好!"); +// 输出 -> "晚上好!" ``` ### Switch @@ -805,6 +885,68 @@ int main(void) { } ``` +### Warning 和 Error + + +在 C 语言中,警告(Warning)和错误(Error)是编译器用于标识代码潜在问题或阻止代码编译的两种机制 + +**警告**: +警告提示代码中可能存在的问题,但不会阻止代码编译。处理警告可以提升代码质量和可移植性。 + +**常见警告示例**: +1. 未使用的变量 +`int x; printf("%d",x);` +2. 类型隐式转换(可能导致数据丢失) +`int x = 3.14; //浮点数被隐式转换` +`int a = 2147483647 + 1; //可能溢出` +3. 函数声明与定义不匹配 + +**错误**: +警告提示代码中可能存在的问题,但不会阻止代码编译。处理警告可以提升代码质量和可移植性。 + +**常见错误示例**: +1. 语法错误(如缺少分号) +`int x=1 ` +2. 函数定义冲突 +```C +void func(int); +void func(double); +``` +3. 函数或变量未定义 +`y = 10; printf("%d",y);` +4. 头文件缺失或冲突 +`#include ` + +**使用编译器指令控制警告和错误**: +1. 抑制警告 +可以使用编译器选项来关闭特定的警告,例如在 GCC 中: +```GCC +gcc -w file.c # 禁用所有警告 +gcc -Wall file.c # 启用所有常见警告 +gcc -Werror file.c # 将警告视为错误 +``` +2. 使用 #pragma 控制警告 +在某些编译器中,可以使用`#pragma`指令启用或禁用警告 +```C +#include +#pragma warning(disable : 4996) // 禁用警告(适用于 MSVC 编译器) + +int main() { + printf("Hello, world!"); + return 0; +} +``` + +**总结** +| 区别点 | Warning(警告) | Error(错误) | +|------------------|----------------------------------------|----------------------------------------| +| 严重程度 | 程序可继续编译,但可能存在隐患 | 编译无法完成,必须修复 | +| 编译结果 | 生成可执行文件 | 无法生成可执行文件 | +| 触发原因 | 潜在问题,例如隐式转换或未使用的变量 | 语法或语义错误,例如语法错误或未定义变量 | +| 修复必要性 | 可选择修复,但建议修复以避免潜在问题 | 必须修复才能继续编译 | +| 编译器选项调整 | 可以忽略或转换为错误(如 `-Werror`) | 无法调整,必须修复 | + + 函数 ----