From e7b8958368448922e3f1586ae7420572a666a971 Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Wed, 1 Jan 2025 21:33:24 +0800 Subject: [PATCH] doc: update c.md document (#913) --- docs/c.md | 619 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 374 insertions(+), 245 deletions(-) diff --git a/docs/c.md b/docs/c.md index 3611819..56e9fd0 100644 --- a/docs/c.md +++ b/docs/c.md @@ -7,7 +7,6 @@ C 备忘清单 ---- ### hello.c - ```c #include @@ -35,40 +34,51 @@ $ ./hello ```c -int myNum = 15; +int myNum = 15; // 定义并初始化变量 myNum +int myNum2; // 声明变量 myNum2 +myNum2 = 15; // 初始化变量 myNum2 -int myNum2; // 声明变量 myNum2 -// 变量声明后第一次赋值我们称为初始化 -// 如果 初始化 和 赋值 在同一行 -// 那么我们可以直接称为 定义变量 myNum2 -myNum2 = 15; +int myNum3 = 15; // 定义并初始化变量 myNum3 +myNum3 = 10; // 重新赋值 myNum3 +``` -int myNum3 = 15; // myNum3 值为 15 -myNum3 = 10; // 现在 myNum3 值为 10 +定义不同类型的变量 -float myFloatNum = 5.99; // 浮点数 -char myLetter = 'D'; // 字符 +```c +// 定义并初始化浮点数变量 +float myFloatNum = 5.99; +// 定义并初始化字符变量 +char myLetter = 'D'; +``` -int x = 5; -int y = 6; -int sum = x + y; // 添加变量相加 -// 声明多个变量 +变量相加 + +```c +int x = 5, y = 6; +int sum = x + y; // 变量相加 +``` + +声明并初始化多个变量 + +```c int x = 5, y = 6, z = 50; int a, b, c = 10; +``` -//仅声明变量不初始化 +仅声明变量不初始化 + +```c int result; -// 如果未初始化,变量的值是未定义的,使用它会导致错误的结果。 -// 此时,变量的值是随机的,因此在使用该变量之前必须进行初始化。 -result = result + 10; // 错误:未初始化的变量 result 会导致不可预测的结果 - -// 部分编译器会输出 Warning,警告未初始化的变量可能导致未定义行为。 +// 未初始化的变量 result 会导致不可预测的结果 +result = result + 10; // 错误:未初始化的变量 +// 部分编译器会警告未初始化的变量可能导致未定义行为 ``` ### 常量 Constants + -常量在 C 语言中我们一般理解为不能被改变的值,活用常量与符号常量,可以使代码更加清晰和安全 +常量是不能被改变的值,使用常量可以使代码更清晰和安全。 ```c const int minutesPerHour = 60; @@ -81,37 +91,53 @@ const float PI = 3.14; const int BIRTHYEAR = 1980; ``` -说明与补充: -1. **常量命名规范**:常量通常使用全大写字母,多个单词之间用下划线分隔(例如 BIRTHYEAR、MAX_LENGTH)。 +#### **命名规范** + -2. **`#define` 与 `const`**: - - **`#define`**:宏常量通常在预处理阶段进行替换,不进行类型检查; - - **`const`**:类型安全的常量,编译器可以检查类型,一般更推荐使用 `const` +常量通常使用全大写字母,单词间用下划线分隔(如 BIRTHYEAR、MAX_LENGTH)。 -3. **数组大小**:可以使用 `const` 来定义数组的常量大小,这样编译器会将其作为编译时常量处理 +#### **数组大小** + +使用 `const` 定义数组大小,编译器将其作为编译时常量处理。 +#### **`#define` 与 `const`** + + +- `#define`:宏常量在预处理阶段替换,不进行类型检查 +- `const`:类型安全的常量,编译器可检查类型,推荐使用 + +#### **注意事项** + +- `const` 常量在定义时必须初始化,否则会导致编译错误。 +- `const` 常量的值不能被修改,任何尝试修改 `const` 常量的操作都会导致编译错误。 +- 使用 `const` 常量可以提高代码的可读性和可维护性,避免魔法数字的使用。 ### 注释 ```c -// 这是一个注释 -printf("Hello World!"); // 这是一个注释 +// 这是一个单行注释 +printf("Hello World!"); // 行内注释 + /* - 多行注释:用于注释跨多行的内容 - 上面的代码将打印出 Hello World! 到屏幕上 + 多行注释: + 用于注释跨多行的内容 注意:多行注释不能嵌套,否则会导致编译错误 */ ``` -**注意**: -单行注释`//`可以嵌套,`////////这种注释也是对的` -但行内注释应避免过长,以免影响代码可读性 -多行注释不能嵌套,否则会导致编译错误(详见下文 [### Warning 和 Error](#warning-和-error) ) +**注意**: + +- 单行注释 `//` 可以嵌套,如 `/////`。 +- 行内注释应避免过长,以免影响代码可读性。 +- 多行注释不能嵌套,否则会导致编译错误。 + ```c /* 这是一个多行注释的开始 - /* 这是嵌套的多行注释,C语言不支持 */ + /* 嵌套的多行注释,C语言不支持 */ +*/ ``` + ### 打印文本 @@ -126,21 +152,34 @@ printf("Value = %f", f); short a = 0b1010110; // 2 进制数字 int b = 02713; // 8 进制数字 long c = 0X1DAB83; // 16 进制数字 -//变量a和c分别为short和long型,所以输出必须加上对应的修饰符h和l +``` -// 以 8 进制形式输出 +变量a和c分别为 `short` 和 `long` 型,所以输出必须加上对应的修饰符 `h` 和 `l` + +#### 以 8 进制形式输出 + +```c printf("a=%ho, b=%o, c=%lo\n", a, b, c); // 输出 => a=126, b=2713, c=7325603 +``` -// 以 10 进制形式输出 +#### 以 10 进制形式输出 + +```c printf("a=%hd, b=%d, c=%ld\n", a, b, c); // 输出 => a=86, b=1483, c=1944451 +``` -// 以 16 进制形式输出(字母小写) +#### 以 16 进制形式输出(字母小写) + +```c printf("a=%hx, b=%x, c=%lx\n", a, b, c); // 输出 => a=56, b=5cb, c=1dab83 +``` -// 以 16 进制形式输出(字母大写) +#### 以 16 进制形式输出(字母大写) + +```c printf("a=%hX, b=%X, c=%lX\n", a, b, c); // 输出 => a=56, b=5CB, c=1DAB83 ``` @@ -169,73 +208,75 @@ printf("%-9d %-9d %-9d\n", d1, d2, d3); 34 0 23 ``` -`%-9d` 中,`d` 表示以 `10` 进制输出,`9` 表示最少占 `9` 个字符的宽度,宽度不足以空格补齐,`-` 表示左对齐,如果不使用左对齐则默认右对齐 +解释:`%-9d`:`d` 表示十进制输出,`9` 表示最少占 9 个字符宽度,`-` 表示左对齐,不使用 `-` 则默认右对齐。 + +对于整型数据: -对于整型数据,假设: ```c int a = 12345; -printf(“%md”,a); +printf("%md", a); ``` -1. 若 m <= 实际数据的宽度,则按实际情况输出 -2. 若 m > 实际数据的宽度,则在实际数据的左边用空格补齐 -3. `printf(“%0md”,a);` 则实际的结果不够 m 位的在数据的左边用0补齐 -对于浮点型数据,**数据的宽度=整数部分的位数+小数点+小数部分的宽度** -假设: +- 若 `m <=` 实际数据宽度,则按实际情况输出。 +- 若 `m >` 实际数据宽度,则在左边用空格补齐。 +- `printf("%0md", a);` 则在左边用 `0` 补齐。 + +对于浮点型数据: + ```c float a = 1.2345; -printf(“%m.nf”,a); //m --整个数据的宽度,n--小数位数 +printf("%m.nf", a); +// m -- 整个数据宽度,n -- 小数位数 ``` -1. 实际小数位数>n,截去小数右边多余的小数,截去的第一位要注意四舍五入 -2. 实际小数位数< n,在小数的最后补0 -3. 若m省略则写作%.n ,整数部分按照实际输出,小数部分按照以上两个规则进行 -4. m < n+1,自动突破宽度为m的限制,按照实际数据进行输出 -5. m > n+1,整个数据的最左边补空格 +- 实际小数位数 `> n`,截去多余小数,注意四舍五入。 +- 实际小数位数 `< n`,在小数最后补 `0`。 +- 若 `m` 省略则写作 `%.n`,整数部分按实际输出,小数部分按以上规则。 +- 若 `m < n+1`,自动突破宽度限制,按实际数据输出。 +- 若 `m > n+1`,左边补空格。 -### 字符串 Strings -在C语言中,字符串是以 `\0` 结尾的字符数组,而不是一种单独的数据类型 -可以通过字符数组来表示字符串 +### 字符串 (Strings) +在 C 语言中,字符串是以 `\0` 结尾的字符数组,而不是一种单独的数据类型。可以通过字符数组来表示字符串。 + +#### 定义并打印字符串 -定义并打印字符串 ```c char greetings[] = "Hello World!"; printf("%s", greetings); ``` -访问字符串中的字符 +#### 访问字符串中的字符 ```c char greetings[] = "Hello World!"; printf("%c", greetings[0]); -//这里我们访问字符串 greetings 的第一个字符'H' ``` -修改字符串中的字符 +访问字符串 `greetings` 的第一个字符 `H` + +#### 修改字符串中的字符 ```c char greetings[] = "Hello World!"; -greetings[0] = 'J'; //// 修改第一个字符为 'J' +greetings[0] = 'J'; // 修改第一个字符为 'J' printf("%s", greetings); // 输出 "Jello World!" ``` -另一种创建字符串的方法 +#### 另一种创建字符串的方法 ```c char greetings[] = {'H','e','l','l','\0'}; printf("%s", greetings); -// 输出 "Hell!" +// 输出 "Hell" ``` -C语言中**没有**`String`类型,字符串是由字符数组(Array)`char[]`来表示的,且必须以 \0 结尾以标识字符串的结束 - +**注意**:C 语言中没有 `String` 类型,字符串是由字符数组 `char[]` 表示的,且必须以 `\0` 结尾以标识字符串的结束。 ### 条件判断 - ```c int time = 20; @@ -245,6 +286,7 @@ if (time < 18) { printf("晚上好!"); } // 输出 -> "晚上好!" + int time = 22; if (time < 10) { printf("早上好!"); @@ -265,25 +307,40 @@ if (time > 8) { // 输出 -> "中午好!" ``` +#### 说明 + +- `if` 语句用于根据条件执行代码块。 +- `else` 语句在 `if` 条件不满足时执行。 +- `else if` 语句用于检查多个条件。 +- 可以嵌套 `if` 语句以检查多个条件。 + ### 三元运算符 - -三元运算符(? :)是一种简洁的条件判断方式,常用于根据条件选择表达式的值,由三个部分组成: -- 一个条件表达式 -- 条件为真时的结果 -- 条件为假时的结果 -基本语法:`(condition) ? expression1 : expression2;` -如果`condition`为真,则返回`expression1`否则返回`expression2`。 + +三元运算符(`? :`)是一种简洁的条件判断方式,用于根据条件选择表达式的值。由三个部分组成: + +- 条件表达式 +- 条件为真时的结果 +- 条件为假时的结果 + +基本语法:`(条件) ? 表达式1 : 表达式2;` +如果 `条件` 为真,则返回 `表达式1`,否则返回 `表达式2`。 + +#### 示例 ```c int time = 20; -(time < 18) ? printf("再会!") : printf("晚上好!"); +(time < 18) ? printf("再会!") + : printf("晚上好!"); // 输出 -> "晚上好!" ``` -三元运算符可以嵌套使用,但嵌套层级太多会导致代码可读性下降,不建议在实际场景使用 +嵌套使用示例(不建议过多嵌套): + ```c int time = 22; -printf((time < 10) ? "早上好!" : (time < 20) ? "再会!" : "晚上好!"); +printf((time < 10) ? "早上好!" + : (time < 20) ? "再会!" + : "晚上好!"); // 输出 -> "晚上好!" ``` @@ -295,32 +352,36 @@ int day = 4; switch (day) { case 3: printf("周三"); break; case 4: printf("周四"); break; - default: - printf("期待周末"); + default: printf("期待周末"); } -// 输出 -> "周四" (day 4) -/* 解释: -switch 语句会根据表达式 day 的值来跳转到匹配的 case 标签 -匹配到 case 4 时,会执行相应的代码并通过 break 跳出 switch 语句 -如果没有匹配到任何 case,则会执行 default 语句(如果存在) -*/ +// 输出 -> "周四" ``` -注意: -1. switch 后面括号中的表达式可以是整型、字符型和枚举型 -2. 在`case`后的各常量表达式的值不能相同 -3. 在`case`后,允许有多个语句,可以不用{ }括起来,而整个 switc h结构一定要有一对{} -4. 各`case`和`default`语句的先后顺序可以改变,不影响程序执行结果 -5. `break`语句用于结束 switch,如果没有`break`,程序会穿透到下一个`case`继续执行,例如 + +#### 说明 + +- `switch` 语句根据表达式的值跳转到匹配的 `case` 标签。 +- 匹配到 `case` 后执行相应代码,并通过 `break` 跳出 `switch`。 +- 如果没有匹配到任何 `case`,则执行 `default` 语句(如果存在)。 + +#### 注意事项 + +- `switch` 表达式可以是整型、字符型和枚举型。 +- `case` 后的常量表达式值不能相同。 +- `case` 后可以有多个语句,不需要 `{ }` 括起来。 +- `case` 和 `default` 语句的顺序不影响程序执行结果。 +- `break` 语句用于结束 `switch`,如果没有 `break`,程序会继续执行下一个 `case`。 + +#### 示例 + ```c int day = 3; switch (day) { case 3: printf("周三"); case 4: printf("周四"); break; - default: - printf("期待周末"); + default: printf("期待周末"); } -// 输出 -> "周三周四" +// 输出 -> "周三周四" ``` ### While 循环 @@ -332,14 +393,53 @@ while (i < 5) { printf("%d\n", i); i++; } -/*解释: -在 while 循环中,首先检查条件 i < 5 是否为真 -如果为真,程序进入循环体,执行打印操作并增加 i 的值 -循环会继续进行,直到 i 达到 5,此时条件 i < 5 不再为真,循环结束 -*/ +// 输出 -> 0 1 2 3 4 ``` -**注意**:不要忘记在循环体内修改循环条件中的变量(如 i++),否则循环将永远执行下去,成为“死循环” +#### 解释 + +- `while` 循环首先检查条件 `i < 5` 是否为真。 +- 如果为真,程序进入循环体,执行打印操作并增加 `i` 的值。 +- 循环会继续进行,直到 `i` 达到 5,此时条件 `i < 5` 不再为真,循环结束。 + +#### 打印 1 到 10 的数字 + +```c +int i = 1; + +while (i <= 10) { + printf("%d\n", i); + i++; +} +// 输出 -> 1 2 3 4 5 6 7 8 9 10 +``` + +#### 打印偶数 + +```c +int i = 0; + +while (i <= 10) { + if (i % 2 == 0) { + printf("%d\n", i); + } + i++; +} +// 输出 -> 0 2 4 6 8 10 +``` + +#### 无限循环(需手动终止) + +```c +int i = 0; + +while (1) { + printf("无限循环\n"); + i++; + if (i == 5) break; // 添加条件以退出循环 +} +// 输出 -> 无限循环 (打印 5 次) +``` ### Do/While 循环 @@ -350,33 +450,55 @@ do { printf("%d\n", i); i++; } while (i < 5); -/*解释: -在 do/while 循环中,循环体至少执行一次,因为条件检查是在循环体执行之后进行的 -首先执行 do 中的代码,然后检查条件 i < 5 是否为真 -如果为真,继续执行循环;如果为假,则退出循环 -/* +// 输出 -> 0 1 2 3 4 ``` -**注意**:与`while`循环不同,`do/while`循环会确保至少执行一次循环体,即使条件一开始就为假 -例如,以下代码虽然条件`i < 5`初始时为假,但仍然会执行一次: -```C + +#### 解释 + +- `do/while` 循环至少执行一次循环体,因为条件检查在循环体执行之后进行。 +- 首先执行 `do` 中的代码,然后检查条件 `i < 5` 是否为真。 +- 如果为真,继续执行循环;如果为假,则退出循环。 + +#### 打印从 5 开始的数字,直到条件不满足 + +```c int i = 5; do { printf("%d\n", i); // 输出 5 i++; } while (i < 5); +// 输出 -> 5 +``` + +#### 计算 1 到 10 的和 + +```c +int i = 1; +int sum = 0; + +do { + sum += i; + i++; +} while (i <= 10); + +printf("Sum: %d\n", sum); +// 输出 -> Sum: 55 ``` ### For 循环 -语法: -```C -for(表达式 1;表达式 2;表达式 3){ + +```c +for (表达式1; 表达式2; 表达式3) { 循环体语句; } ``` -表达式 1:设置初始条件,只执行一次,为 0 个或多个变量设置初值 -表达式 2:是循环条件表达式,用来判定是否继续循环。在每次执行循环体之前要先执行表达式 2,然后再决定是否继续执行循环 -表达式 3:作为循环的调整,比如是循环体变量增值,它是执行循环体语句之后再执行 + +- 表达式1:设置初始条件,只执行一次。 +- 表达式2:循环条件表达式,每次循环前检查。 +- 表达式3:循环体执行后的调整操作。 + +示例: ```c int i; @@ -384,40 +506,28 @@ int i; for (i = 0; i < 5; i++) { printf("%d\n", i); } -/* 输出: -0 -1 -2 -3 -4 -*/ +// 输出 -> 0 1 2 3 4 ``` -**注意**: -1. for 语句的三个表达式不是必须的 -2. 当条件表达式(表达式 2)的值为假(为 0)时 for 循环语句就结束 -3. 可以在循环体内执行`break`,`continue`,`goto`语句 -4. 若表达式 2 是空的,表明表达式 2 的值一直是真,即死循环 -如:`for(;;) //死循环语句 相当于while(1)` +#### 注意事项 -**变体**: -- `for(i = m; i < n; i++)`会从 i = m 开始到 i = n-1,循环 n - m 次 -- `for(i = m; i <= n; i++)`会从 i = m 到 i = n,循环 n - m + 1 次 +- `for` 语句的三个表达式不是必须的。 +- 当条件表达式(表达式2)为假时,`for` 循环结束。 +- 可以在循环体内使用 `break`、`continue`、`goto` 语句。 +- 如果表达式2为空,则表示无限循环,如 `for(;;)` 相当于 `while(1)`。 +#### 变体 +- `for (i = m; i < n; i++)` 从 `i = m` 开始到 `i = n-1`,循环 `n - m` 次。 +- `for (i = m; i <= n; i++)` 从 `i = m` 到 `i = n`,循环 `n - m + 1` 次。 +### 跳出循环 (Break/Continue/Goto) + +#### `break` 语句 -### 跳出循环(中断语句) Break/Continue/Goto - -`break`语句:跳出本层循环,执行循环后的语句 -`continue`语句:跳出本次循环,执行下一次循环 -`goto`语句:跳出到指定的标号位 +跳出当前循环或 `switch` 语句,执行后续代码。 -**1.`break`语句**: - -`break`用于跳出当前的循环或`switch`语句,直接跳到循环或`switch`语句之后的下一条语句 -通常用于在特定条件下提前结束循环 ```c int i; @@ -427,16 +537,13 @@ for (i = 0; i < 10; i++) { } printf("%d\n", i); } -//输出: -//0 1 2 3 4(换行符使用空格代替) +// 输出 -> 0 1 2 3 ``` -当`i`等于 4 时,`break`语句使得循环提前结束,因此没有打印出 4 及之后的值 +#### `continue` 语句 -**2.`continue`语句**: +跳过当前循环的剩余语句,直接进入下一次循环。 -`continue`用于跳过当前循环中的剩余语句(在for循环中相当于直接执行表达式3),直接进入下一次循环的条件判断阶段 -通常用于跳过某些特定的循环迭代 ```c int i; @@ -446,17 +553,14 @@ for (i = 0; i < 10; i++) { } printf("%d\n", i); } -//输出: -//0 1 2 3 5 6 7 8 9(换行符使用空格代替) +// 输出 -> 0 1 2 3 5 6 7 8 9 ``` -当`i`等于 4 时,`continue`会跳过打印语句,因此 4 被跳过,不会输出 +#### `goto` 语句 -**3.`goto`语句**: +无条件跳转到指定标签位置。 -`goto`用于无条件跳转到程序中的指定标签位置 - -```C +```c int i = 0; while (i < 10) { @@ -469,56 +573,20 @@ while (i < 10) { skip: printf("Exited the loop at i = %d\n", i); -/* 输出: -0 -1 -2 -3 -Exited the loop at i = 4 -*/ +// 输出 -> 0 1 2 3 Exited the loop at i = 4 ``` -`goto skip`语句将程序的控制流跳转到标签`skip`处,导致循环在`i = 4`时直接结束,并输出`Exited the loop at i = 4` +#### 注意事项 -**注意**: -1. `label标签`必须是在当前函数内定义的标签。标签的命名规则与变量的命名规则相同,但标签不能与C语言的关键字冲突 -2. `goto`语句通常用于跳转到同一函数内的某个位置,但也可以跳转到同一文件中的其他函数内的标签(不推荐) -3. goto语句应慎用,因为过多或滥用goto语句可能会导致代码逻辑混乱、难以维护和阅读。通常情况下,可以使用循环或条件语句等结构化的控制流语句来代替goto语句 +- 标签必须在当前函数内定义,命名规则与变量相同。 +- `goto` 语句应慎用,避免代码逻辑混乱,通常使用循环或条件语句代替。 -### 数组 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; @@ -566,6 +634,35 @@ switch(day){ } ``` +### 数组 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]); // 输出 33 +``` + +#### 循环遍历数组 + +```c +int myNumbers[] = {25, 50, 75, 100}; +int i; + +for (i = 0; i < 4; i++) { + printf("%d\n", myNumbers[i]); +} +// 输出 -> 25 50 75 100 +``` + ### 用户输入 ```c @@ -597,39 +694,27 @@ printf("Hello %s.", firstName); ### 内存地址 -创建变量时,会为该变量分配一个内存地址 +创建变量时,会为该变量分配一个内存地址。 ```c int myAge = 43; - printf("%p", &myAge); -// 输出:0x7ffe5367e044 +// 输出 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 的地址 +int myAge = 43; // 一个 int 变量 +int *ptr = &myAge; // 创建指向 myAge 的指针 -printf("%d\n", myAge); // 输出 myAge (43) 的值 - -printf("%p\n", &myAge); // 输出 myAge 的内存地址(0x7ffe5367e044) - -printf("%p\n", ptr); // 用指针(0x7ffe5367e044)输出myAge的内存地址 +printf("%d\n", myAge); // 输出 myAge 的值 -> 43 +printf("%p\n", &myAge); // 输出 myAge 的内存地址,例如:0x7ffe5367e044 +printf("%p\n", ptr); // 输出指针 ptr 的值(即 myAge 的内存地址) +printf("%d\n", *ptr); // 通过指针访问 myAge 的值 -> 43 ``` ### 取消引用 @@ -645,6 +730,18 @@ printf("%p\n", ptr); printf("%d\n", *ptr); ``` +### 指针变量 + + +```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的内存地址 +``` + 运算符 --- @@ -987,46 +1084,78 @@ int main(void) { ### Warning 和 Error -在 C 语言中,警告(Warning)和错误(Error)是编译器用于标识代码潜在问题或阻止代码编译的两种机制 +在 C 语言中,警告(Warning)和错误(Error)是编译器用于标识代码潜在问题或阻止代码编译的机制。 + +#### 警告 -**警告**: 警告提示代码中可能存在的问题,但不会阻止代码编译。处理警告可以提升代码质量和可移植性。 -**常见警告示例**: -1. 未使用的变量 -`int x; printf("%d",x);` -2. 类型隐式转换(可能导致数据丢失) -`int x = 3.14; //浮点数被隐式转换` -`int a = 2147483647 + 1; //可能溢出` -3. 函数声明与定义不匹配 +#### **常见警告示例** -**错误**: -警告提示代码中可能存在的问题,但不会阻止代码编译。处理警告可以提升代码质量和可移植性。 +未使用的变量 + +```c +int x; printf("%d", x); +``` + +类型隐式转换(可能导致数据丢失) + +```c +int x = 3.14; // 浮点数被隐式转换 +int a = 2147483647 + 1; // 可能溢出 +``` + +函数声明与定义不匹配 + +#### 错误 + +错误会阻止代码编译,必须修复才能继续编译。 **常见错误示例**: -1. 语法错误(如缺少分号) -`int x=1 ` -2. 函数定义冲突 -```C + +语法错误(如缺少分号) + +```c +int x = 1 +``` + +函数定义冲突 + +```c void func(int); void func(double); ``` -3. 函数或变量未定义 -`y = 10; printf("%d",y);` -4. 头文件缺失或冲突 -`#include ` -**使用编译器指令控制警告和错误**: -1. 抑制警告 +函数或变量未定义 + +```c +y = 10; printf("%d", y); +``` + +头文件缺失或冲突 + +```c +#include +``` + +### 使用编译器指令控制警告和错误 + + +#### 抑制警告 + 可以使用编译器选项来关闭特定的警告,例如在 GCC 中: -```GCC + +```sh gcc -w file.c # 禁用所有警告 gcc -Wall file.c # 启用所有常见警告 gcc -Werror file.c # 将警告视为错误 ``` -2. 使用 #pragma 控制警告 -在某些编译器中,可以使用`#pragma`指令启用或禁用警告 -```C + +#### 使用 `#pragma` 控制警告 + +在某些编译器中,可以使用 `#pragma` 指令启用或禁用警告: + +```c #include #pragma warning(disable : 4996) // 禁用警告(适用于 MSVC 编译器) @@ -1036,7 +1165,8 @@ int main() { } ``` -**总结** +#### 总结 + | 区别点 | Warning(警告) | Error(错误) | |------------------|----------------------------------------|----------------------------------------| | 严重程度 | 程序可继续编译,但可能存在隐患 | 编译无法完成,必须修复 | @@ -1045,7 +1175,6 @@ int main() { | 修复必要性 | 可选择修复,但建议修复以避免潜在问题 | 必须修复才能继续编译 | | 编译器选项调整 | 可以忽略或转换为错误(如 `-Werror`) | 无法调整,必须修复 | - 函数 ----