文章目录
- 12 操作符
- 🍒算术操作符
- 🍒关系操作符
- 🍒逻辑操作符
- 🍒位操作符
- 🍒赋值操作符
- 🍒强制类型转换符
- 🍒成员访问操作符
- :fire:操作符优先级
- 计算大小符`sizeof`
- 条件操作符 `? :`
- `const char *`
- 按位取反
- `snprintf`字符串输出函数
12 操作符
🍒算术操作符
- 加法 (
+
): 加法操作。 - 减法 (
-
): 减法操作。 - 乘法 (
*
): 乘法操作。 - 除法 (
/
): 除法操作。 - 取模 (
%
): 返回两个数相除的余数。
#include <stdio.h>int main() {// 算术操作符int a = 10, b = 3;printf("Arithmetic Operators:\n");printf("a + b = %d // Expected: 13\n", a + b); // 加法printf("a - b = %d // Expected: 7\n", a - b); // 减法printf("a * b = %d // Expected: 30\n", a * b); // 乘法printf("a / b = %d // Expected: 3\n", a / b); // 除法, 注意这是整数除法printf("a %% b = %d // Expected: 1\n\n", a % b); // 取模, 注意%%用于打印%return 0;
}
🍒关系操作符
在 C 语言中,关系操作符同样用于比较两个值或表达式,并基于比较的结果返回一个布尔值,即 0 (表示 False
)或 1 (表示 True
)。C 语言中的关系操作符包括:
==
:等于。如果两边的值相等,返回 1;否则返回 0。!=
:不等于。如果两边的值不相等,返回 1;否则返回 0。<
:小于。如果左边的值小于右边的值,返回 1;否则返回 0。>
:大于。如果左边的值大于右边的值,返回 1;否则返回 0。<=
:小于或等于。如果左边的值小于或等于右边的值,返回 1;否则返回 0。>=
:大于或等于。如果左边的值大于或等于右边的值,返回 1;否则返回 0。
#include <stdio.h>int main() {int a = 10, b = 3;printf("Relational Operators:\n");// 等于printf("a == b: %d\n", a == b); // Expected: 0 (false)// 不等于printf("a != b: %d\n", a != b); // Expected: 1 (true)// 大于printf("a > b: %d\n", a > b); // Expected: 1 (true)// 小于printf("a < b: %d\n", a < b); // Expected: 0 (false)// 大于等于printf("a >= b: %d\n", a >= b); // Expected: 1 (true)// 小于等于printf("a <= b: %d\n", a <= b); // Expected: 0 (false)return 0;
}
🍒逻辑操作符
在 C 语言中,逻辑操作符用于组合或修改条件表达式的布尔值,以实现复杂的逻辑判断。C 语言中的逻辑操作符包括:
-
逻辑与 (
&&
):如果两个操作数都非零(即都为真),则条件成立(返回 1),否则条件不成立(返回 0)。 -
逻辑或 (
||
):如果两个操作数中至少有一个非零(即至少有一个为真),则条件成立(返回 1),否则条件不成立(返回 0)。 -
逻辑非 (
!
):用于反转操作数的逻辑状态。如果条件为真(非零),则逻辑非操作符将使其变为假(0);如果条件为假(0),则操作符将使其变为真(1)。
示例 1:使用逻辑与(&&
)
#include <stdio.h>int main() {int age = 25;int score = 85;// 检查年龄是否在20到30之间,并且分数是否高于80if (age >= 20 && age <= 30 && score > 80) {printf("Candidate is selected.\n");} else {printf("Candidate is not selected.\n");}return 0;
}
示例 2:使用逻辑或(||
)
#include <stdio.h>int main() {float temperature = 35.5;int isRaining = 1; // 用 1 表示下雨,0 表示没有下雨// 检查是否过热或下雨if (temperature > 30 || isRaining) {printf("It's not a good day for a picnic.\n");} else {printf("It's a good day for a picnic.\n");}return 0;
}
示例 3:使用逻辑非(!
)
#include <stdio.h>int main() {int doorClosed = 1; // 用 1 表示门关闭,0 表示门开启// 检查门是否开启if (!doorClosed) {printf("The door is open.\n");} else {printf("The door is closed.\n");}return 0;
}
注意
在逻辑表达式中,C 语言采用短路求值(short-circuit evaluation):
- 在使用
&&
操作符的表达式中,如果第一个操作数的值为假(0),则不会评估第二个操作数,因为整个表达式的结果已确定为假(0)。- 在使用
||
操作符的表达式中,如果第一个操作数的值为真(非0),则不会评估第二个操作数,因为整个表达式的结果已确定为真(1)。这种行为可以用来防止执行可能导致错误的操作,例如在访问数组元素或指针之前先检查它们是否有效。
🍒位操作符
- 按位与 (
&
): 对两个操作数中相对应的位执行逻辑与操作。 - 按位或 (
|
): 对两个操作数中相对应的位执行逻辑或操作。 - 按位异或 (
^
): 对两个操作数中相对应的位执行逻辑异或操作。 - 按位取反 (
~
): 对操作数的每一位执行逻辑取反操作。 - 左移 (
<<
): 把左操作数的位向左边移动指定的位数。 - 右移 (
>>
): 把左操作数的位向右边移动指定的位数。
#include <stdio.h>int main() {unsigned int a = 5; // 二进制: 0101unsigned int b = 9; // 二进制: 1001int result;// 按位与result = a & b; // 二进制: 0001, 十进制: 1printf("a & b = %d\n", result);// 按位或result = a | b; // 二进制: 1101, 十进制: 13printf("a | b = %d\n", result);// 按位异或result = a ^ b; // 二进制: 1100, 十进制: 12printf("a ^ b = %d\n", result);// 按位取反result = ~a;// 注意:由于result是int类型,按位取反的结果将依赖于int的位数(假设是32位,实际的输出会是补码形式的一个负数)printf("~a = %d\n", result);// 左移result = a << 1; // 二进制: 1010, 十进制: 10printf("a << 1 = %d\n", result);// 右移result = a >> 1; // 二进制: 0010, 十进制: 2printf("a >> 1 = %d\n", result);return 0;
}//a& b = 1
//a | b = 13
//a ^ b = 12
//~a = -6
//a << 1 = 10
//a >> 1 = 2
🍒赋值操作符
在 C 语言中,赋值操作符用于给变量赋值。最基本的赋值操作符是等号 (=
),它将右侧表达式的值赋给左侧的变量。此外,C 语言还提供了一系列复合赋值操作符,这些操作符结合了算术操作和赋值操作,可以使代码更加简洁。
基本赋值操作符
=
:将右侧表达式的值赋给左侧的变量。
复合赋值操作符
+=
:加上后赋值,a += b
等价于a = a + b
。-=
:减去后赋值,a -= b
等价于a = a - b
。*=
:乘以后赋值,a *= b
等价于a = a * b
。/=
:除以后赋值,a /= b
等价于a = a / b
。注意,除以零会导致运行时错误。%=
:取模后赋值,a %= b
等价于a = a % b
。对于整数类型,表示取除法的余数。<<=
:左移后赋值,a <<= b
等价于a = a << b
。表示将a
的二进制表示向左移动b
位。>>=
:右移后赋值,a >>= b
等价于a = a >> b
。表示将a
的二进制表示向右移动b
位。&=
:按位与后赋值,a &= b
等价于a = a & b
。只有在a
和b
对应位都为 1 时,结果的对应位才为 1。^=
:按位异或后赋值,a ^= b
等价于a = a ^ b
。只有在a
和b
对应位不同时,结果的对应位才为 1。|=
:按位或后赋值,a |= b
等价于a = a | b
。只要a
或b
的对应位中有一个为 1,结果的对应位就为 1。
#include <stdio.h>int main() {int a = 2;printf("Initial value of a: %d\n", a);// 加上后赋值a += 3; // 等价于 a = a + 3;printf("After a += 3: %d\n", a);// 减去后赋值a -= 1; // 等价于 a = a - 1;printf("After a -= 1: %d\n", a);// 乘以后赋值a *= 2; // 等价于 a = a * 2;printf("After a *= 2: %d\n", a);// 除以后赋值a /= 4; // 等价于 a = a / 4;printf("After a /= 4: %d\n", a);// 取模后赋值a %= 3; // 等价于 a = a % 3;printf("After a %%= 3: %d\n", a);// 左移后赋值a = 1; // Reset a for shift operationsa <<= 2; // 等价于 a = a << 2;printf("After a <<= 2: %d\n", a);// 右移后赋值a >>= 1; // 等价于 a = a >> 1;printf("After a >>= 1: %d\n", a);// 按位与后赋值a &= 5; // 等价于 a = a & 5; (5 in binary: 101) printf("After a &= 5: %d\n", a);// 按位异或后赋值a ^= 3; // 等价于 a = a ^ 3; (3 in binary: 011)printf("After a ^= 3: %d\n", a);// 按位或后赋值a |= 8; // 等价于 a = a | 8; (8 in binary: 1000)printf("After a |= 8: %d\n", a);return 0;
}//Initial value of a : 2
//After a += 3 : 5
//After a -= 1 : 4
//After a *= 2 : 8
//After a /= 4 : 2
//After a %= 3 : 2//a=1
//After a <<= 2 : 4
//After a >>= 1 : 2// 与 &
// 0010 2
// 0101 5
// 0000 0//After a &= 5 : 0//异或 ^
// 0000 0
// 0011 3 异或不同为1
// 0011//After a ^= 3 : 3// 或 |
// 0011 3
// 1000 8
// 1011 11 //After a |= 8 : 11
binary 二进制
🍒强制类型转换符
强制类型转换(Type Casting)允许程序员手动改变一个值的数据类型。
虽然 C 语言在执行表达式时会自动进行类型转换(称为隐式类型转换或自动类型转换),但在某些情况下,程序员需要显式地指定类型转换,以避免自动转换可能带来的精度损失或类型不匹配的问题。
(目标类型) 表达式
示例 1:整数与浮点数之间的转换
将整数 i
强制转换为浮点数,以便在进行除法操作时保留小数部分,避免整数除法的截断行为。
#include <stdio.h>int main() {int i = 10;float f;// 将整数转换为浮点数进行除法操作以保持小数部分f = (float)i / 3;printf("The result of (float)i / 3 is: %f\n", f);return 0;
}//The result of i / 3 is: 3.000000
//The result of (float)i / 3 is: 3.333333
示例 2:字符类型与整数之间的转换
强制类型转换处理字符的 ASCII 值,以及如何将整数转换回字符类型。
#include <stdio.h>int main() {char c = 'A';int x;// 将字符转换为其 ASCII 码的整数值x = (int)c;// 将整数值转换回字符c = (char)(x + 1);printf("Original character was 'A', next character is: '%c'\n", c);return 0;
}
//Original character was 'A', next character is: 'B'
示例 3:提高表达式的计算精度
i1
被强制转换为 double
类型,以保证除法操作的精度,从而避免因为都是整数而导致的结果自动向下取整。
#include <stdio.h>int main() {int i1 = 2, i2 = 3;double result;// 通过强制类型转换确保结果的精度result = (double)i1 / i2;printf("The precise result of 2 / 3 is: %lf\n", result);//The precise result of 2 / 3 is: 0.666667return 0;
}
因为
i1
被强制转换为double
类型,而i2
仍然是int
类型,根据 C 语言的类型提升规则,i2
也会被隐式地转换为double
类型来执行运算。
示例 4:大小不同的数据类型之间的转换
将一个较大的整数值强制转换为一个字符。由于字符类型的存储空间较小,这样的转换可能会导致数据的丢失。这里 1024
转换为字符后的结果依赖于其在字符类型能表示的范围内的值。
#include <stdio.h>int main() {int i = 1024;char c;// 整数转换为字符,可能会丢失数据c = (char)i; // 只会保留 i 的低8位printf("The character representation of 1024 is: '%c'\n", c);return 0;
}
- 整数到字符的转换:
- 通过
(char)i
强制类型转换,整数1024
被转换为char
类型。这种转换只保留整数值的低 8 位
- 数据的“丢失”:
- 因为
1024
(二进制表示为100 0000 0000
)转换为 8 位意味着只保留低 8 位,所以实际上你得到的是0
(二进制的0000 0000
)
- 输出结果:
- 输出的字符实际上是 ASCII 值为
0
的字符,这是一个控制字符(NULL 字符),在控制台上不会显示为可见字符。
🍒成员访问操作符
- 使用
.
操作符来访问一个结构体变量的成员。 - 使用
->
操作符来访问一个指向结构体的指针所指向的成员。
使用.
操作符
当你有一个结构体变量时,可以使用.
操作符直接访问其成员。假设有一个结构体Person
,其中包含两个成员:name
和age
。
#include <stdio.h>typedef struct {char* name;int age;
} Person;int main() {Person person;person.name = "Alice";person.age = 30;printf("%s is %d years old.\n", person.name, person.age);return 0;
}
在这个例子中,person
是一个Person
类型的变量。通过使用.
操作符(例如person.name
和person.age
),可以访问和修改这个结构体的成员。
使用->
操作符
当你有一个指向结构体的指针时,应该使用->
操作符来访问其成员。继续使用上面的Person
结构体为例,但这次我们将使用一个指针来访问它。
#include <stdio.h>typedef struct {char* name;int age;
} Person;int main() {Person person;Person *ptr = &person;ptr->name = "Bob";ptr->age = 25;printf("%s is %d years old.\n", ptr->name, ptr->age);return 0;
}
在这个例子中,ptr
是一个指向Person
类型的指针。通过使用->
操作符(例如ptr->name
和ptr->age
),可以访问和修改指针所指向的结构体的成员。
🔥操作符优先级
在 C 语言中,不同的操作符有不同的优先级。这意味着,如果在一个表达式中同时使用了多个操作符,那么操作符的优先级将决定了这些操作符的执行顺序。以下是 C 语言中各种操作符的优先级列表,从高到低:
-
圆括号
()
:最高优先级,用于改变默认的优先级顺序。 -
单目操作符:如递增 (
++
), 递减 (--
), 逻辑非 (!
), 取反 (~
), 正负号 (+
,-
), 引用 (&
), 解引用 (*
), sizeof 等。 -
算术操作符:乘 (
*
), 除 (/
), 取模 (%
), 加 (+
), 减 (-
)。其中,乘、除、取模的优先级高于加、减。 -
移位操作符:左移 (
<<
), 右移 (>>
). -
关系操作符:小于 (
<
), 小于等于 (<=
), 大于 (>
), 大于等于 (>=
), 等于 (==
), 不等于 (!=
). 其中,小于、小于等于、大于、大于等于的优先级高于等于、不等于。 -
位操作符:按位与 (
&
), 按位异或 (^
), 按位或 (|
). -
逻辑操作符:逻辑与 (
&&
), 逻辑或 (||
). -
条件操作符(三元操作符):
? :
-
赋值操作符:
=
,以及复合赋值操作符如+=
,-=
,*=
,/=
,%=
,<<=
,>>=
,&=
,^=
,|=
。 -
逗号操作符:
,
-
算术操作符优先级
int a = 2;
int b = 3;
int c = a + b * 2; // 首先计算 b * 2,然后将结果加上 a,所以 c 的值是 8,而不是 10。
- 关系操作符和逻辑操作符
int a = 2;
int b = 3;
int c = 4;
int result = a < b && b < c; // 首先计算 a < b 和 b < c,然后将两个结果进行逻辑与操作,所以 result 的值是 1。
- 使用括号改变优先级
int a = 2;
int b = 3;
int c = (a + b) * 2; // 首先计算括号内的 a + b,然后将结果乘以 2,所以 c 的值是 10,而不是 8。
- 赋值操作符和算术操作符
int a = 2;
int b = 3;
a *= b + 2; // 首先计算 b + 2,然后将结果乘以 a,所以 a 的新值是 10。
- 位操作符和关系操作符
int a = 2; // 二进制表示为 0010
int b = 3; // 二进制表示为 0011
int result = a & b > 1; // 首先计算 a & b,然后将结果和 1 进行比较,所以 result 的值是 1。
- 移位操作符和算术操作符
int a = 1;
int b = a << 2 + 1; // 首先计算 2 + 1,然后将 a 左移得到的位数,所以 b 的值是 8。
- 三元操作符和算术操作符
int a = 2;
int b = 3;
int c = a > b ? a + b : a - b; // 首先计算 a > b,根据结果选择执行 a + b 还是 a - b,所以 c 的值是 -1。
- 解引用操作符和算术操作符
int a = 2;
int b = 3;
int *p = &a;
int c = *p + b; // 首先获取 p 指向的值,然后将结果加上 b,所以 c 的值是 5。
- 逻辑非操作符和关系操作符
int a = 2;
int b = 3;
int result = !a < b; // 首先计算 !a,然后将结果和 b 进行比较,所以 result 的值是 0。
这些例子应该能帮助你更好地理解操作符优先级在 C 语言中的应用。
计算大小符sizeof
-
计算变量的大小:使用
sizeof
可以获取任意变量占用的内存大小。这不仅适用于基本数据类型,如int
、float
、double
等,也适用于结构体、联合体和数组。int a; size_t size = sizeof(a); // 计算int类型变量a的大小
-
计算数据类型的大小:除了变量,
sizeof
还可以直接用于数据类型,来获取该类型占用的内存大小。size_t intSize = sizeof(int); // 直接计算int类型的大小
-
计算数组的总大小:对于数组,
sizeof
返回整个数组占用的内存大小。这对于计算数组中元素的数量特别有用,尤其是当数组的大小不是手动指定的时候。int arr[10]; size_t arrSize = sizeof(arr); // 计算整个数组的大小
-
计算数组单个元素的大小:结合数组的总大小和单个元素的大小,可以计算出数组中元素的总数。
int arr[10]; size_t numElements = sizeof(arr) / sizeof(arr[0]); // 计算数组中元素的数量
-
计算结构体和联合体的大小:
sizeof
同样适用于结构体和联合体,用于计算它们所占用的内存大小。这对于动态内存分配非常有用。struct MyStruct {int a;double b; }; size_t myStructSize = sizeof(struct MyStruct); // 计算结构体的大小
-
在动态内存分配中的应用:在使用
malloc
或calloc
进行动态内存分配时,sizeof
操作符常用于指定需要分配的内存大小。int *p = (int *)malloc(sizeof(int) * 10); // 分配10个int大小的内存
-
类型安全的内存分配:使用
sizeof
还可以增强代码的类型安全性,避免在内存分配时出现类型错误。int *p = malloc(sizeof(*p) * 10); // 使用*p来确定分配的类型和大小,更安全
条件操作符 ? :
条件操作符 ? :
,也称为三元操作符,它允许在单个表达式内进行简单的条件判断。基本语法是:
condition ? expression1 : expression2;
这里的condition
是一个布尔表达式。如果condition
为真(非0值),则整个条件表达式的结果是expression1
的值;如果为假(0值),则结果是expression2
的值。
示例 1: 基础用法
int score = 75;
const char *result = score >= 60 ? "Passed" : "Failed";
printf("The student has %s the exam.", result);
在这个例子中,如果score
大于或等于60,result
将被赋值为"Passed"
;否则,result
的值将是"Failed"
。
示例 2: 嵌套条件操作符
三元操作符也可以嵌套,以处理更复杂的条件。假设我们现在除了判断是否通过外,还要区分优秀(分数大于等于85分):
int score = 90;
const char *result = score >= 85 ? "Excellent" : score >= 60 ? "Passed" : "Failed";
printf("The student's performance was: %s.", result);
这里,第一个条件判断是否score >= 85
,如果是,结果是"Excellent"
。如果不是,就会进行下一个判断:score >= 60
,如果这个条件为真,结果是"Passed"
,否则是"Failed"
。
const char *
- 初始化和赋值
char *
用于可变字符串:
当你需要一个可修改的字符串时,可以使用char *
配合动态内存分配或使用字符数组。
- 使用动态内存分配:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main() {char *str = (char *)malloc(20); // 分配 20 个字节的内存空间strcpy_s(str, 20, "Hello"); // 初始化字符串,安全地复制strcat_s(str, 20, ", world!"); // 修改字符串,安全地连接printf("%s\n", str); // 打印字符串free(str); // 释放内存return 0;
}
错误 C2440:“初始化”: 无法从“void *”转换为“char *”
在C++中(看起来您是在使用C++编译器编译C代码),
malloc
返回的是void *
类型,而C++是强类型语言,需要显式地将void *
转换为其他类型的指针。因此,需要对malloc
的返回值进行类型转换:char* str = malloc(20); // 错误 C2440:“初始化”: 无法从“void *”转换为“char *” char *str = (char *)malloc(20); // 强制转换 malloc 返回值为 char *
const char *
用于不可变字符串:
当你仅需要访问或传递字符串,而不需要修改它时,应该使用const char *
。
#include <stdio.h>int main() {const char *str = "Hello, world!";printf("%s\n", str); // 打印字符串// str[0] = 'h'; // 这将产生编译错误return 0;
}
这个例子中,str
指向的字符串是不可修改的,任何尝试修改它的操作都会导致编译错误。
- 函数参数
使用char *
作为函数参数允许函数修改字符串:
#include <stdio.h>
#include <string.h>void appendExclamationMark(char *str) {strcat(str, "!");
}int main() {char greeting[20] = "Hello, world";appendExclamationMark(greeting);printf("%s\n", greeting); // 输出 "Hello, world!"return 0;
}
使用const char *
作为函数参数防止函数内部修改字符串:
#include <stdio.h>void printString(const char *str) {printf("%s\n", str);// str[0] = 'h'; // 这会产生编译错误
}int main() {const char *message = "Hello, world!";printString(message); // 安全地打印字符串,不担心被修改return 0;
}
按位取反
当你对一个无符号整数进行按位取反操作时,你实际上是将所有的位从0
变为1
,以及从1
变为0
。在C语言中,整数默认是以补码(two’s complement)形式表示的。补码是一种用二进制表示有符号整数的方法,使得负数的表示和加法运算都变得简单。下面是分析过程:
假设unsigned int a = 5;
,且我们的系统中int
类型是32位的。
-
原始的二进制表示:
- 在32位系统中,
a
的完整32位二进制表示(包括前导零):00000000 00000000 00000000 00000101
- 在32位系统中,
-
进行按位取反操作:
- 对
a
进行~a
操作后的结果是将所有位翻转 变成
11111111 11111111 11111111 11111010`。- 得到的是一个负数的补码(整数默认是以补码形式表示的)
- 对
-
理解补码表示:
- 在补码表示中,
11111111 11111111 11111111 11111010
(或者取反+1) - 先减1:
11111111 11111111 11111111 11111001
- 取反码得到:
00000000 00000000 00000000 00000110
(6
的二进制表示) - 十进制
-6
11111111 11111111 11111111 11111010
- 在补码表示中,
因此,当你在代码中执行printf("~a = %d\n", result);
后,输出会是-6
,前提是int
类型是32位的,并且我们假设系统使用补码表示负数。这个解释依赖于int
类型具体的位数以及补码表示法,这两者在现代计算机系统中都是非常通用的假设。
snprintf
字符串输出函数
snprintf
是一个在 用于格式化字符串输出的函数,属于 stdio.h
头文件。它的主要功能是将格式化的数据写入一个字符串中。
函数原型
int snprintf(char *str, size_t size, const char *format, ...);
str
:目标字符串的指针,格式化后的输出将存储在这里。size
:目标字符串缓冲区的最大长度。snprintf
会确保不会向str
写入超过size - 1
个字符,最后一个位置留给空字符\0
。format
:格式字符串,控制后续参数如何格式化并插入到str
。...
:可变数量的额外参数,这些参数的类型和数量取决于格式字符串中的格式指定符。
返回值
- 成功时,返回欲写入的字符串长度(不包括空字符),即使这个长度大于
size
,也不会实际写入超出size-1
的内容。 - 出错时,返回负值。
使用示例
snprintf
将一个整数和一个浮点数格式化为一个字符串,存储在 buffer
中。同时,它还检查格式化后的字符串是否会超出缓冲区的大小,并相应地处理。
#include <stdio.h>int main() {char buffer[50];int a = 10;float b = 3.14159;// 使用 snprintf 将整数和浮点数格式化到字符串中int num_chars = snprintf(buffer, sizeof(buffer), "Integer: %d, Float: %.2f", a, b);if (num_chars >= 0 && num_chars < sizeof(buffer)) {printf("Formatted string: %s\n", buffer);} else if (num_chars >= sizeof(buffer)) {printf("Buffer too small, required %d characters.\n", num_chars);} else {printf("An error occurred.\n");}return 0;
}
细节
要修改代码以更清晰地表达其意图并解释相关的知识点,我们可以对原始代码进行一些调整。我们将重点放在:
- 缓冲区大小:确保有足够的空间存储整个字符串和末尾的空字符
\0
。 snprintf
的返回值:理解它表示的是尝试写入的字符数,不包括末尾的空字符。- 条件判断:清楚地处理各种情况,包括成功写入、缓冲区过小以及其他潜在错误。
#include <stdio.h>int main() {char buffer[3];char buffer2[4];// 使用 snprintf 将整数和浮点数格式化到字符串中int num_chars = snprintf(buffer, sizeof(buffer), "abc");int num_chars2 = snprintf(buffer2, sizeof(buffer2), "abc");printf("buffer1 %d \n", num_chars);printf("buffer1 %s \n", buffer);printf("buffer2 %d \n", num_chars2);printf("buffer2 %s \n", buffer2);return 0;}
//char buffer[3];
//buffer1 3
//buffer1 ab
//char buffer2[4];
//buffer2 3
//buffer2 abc