跳转至

语法细节

Quote

“魔鬼藏在细节里,bug 也藏在细节里。”

Tip

下面是我刷题过程中遇到的一些语法细节我没注意,但是往往是这一个个细节决定你代码是否能跑得通,《道德经》有言“天下难事,必作于易;天下大事,必作于细。”,所以以下是我对于某些我不熟悉语法的归纳。排序不分先后。


1.C++ 数组是否自动初始化为 0

很多人误以为:

int a[100];
long long dp[100];

定义出来默认就是 0。这个理解不对。

变量是否自动初始化,与 intlong long、数组类型无关,取决于变量定义的位置(存储期)

函数内部定义的局部变量:

int main() {
    int a[10];
}

数组元素默认是未定义值(垃圾值),直接使用可能导致结果错误。

函数外定义的全局变量:

int a[10];

会自动初始化为 0。

static 的变量:

static int a[10];

也会自动初始化为 0。

很多初学者之所以误会,是因为某些编译器或调试环境碰巧把局部内存清零了,但这不是 C++ 语言保证,换平台后可能直接出错。

竞赛中最常见问题是动态规划数组没初始化:

long long dp[1005];
dp[i] += dp[i-1];

此时 dp[i] 初始值是垃圾值,答案会错。

正确写法:

long long dp[1005] = {0};

或:

memset(dp, 0, sizeof(dp));

记忆一句话:

局部变量默认不安全全局/static 默认是0不确定就手动初始化

2.C++ 三目运算符(?:)与“比较写法”

三目运算符是 C++ 中常用的简化判断表达式:

a ? b : c

含义是:如果 a 为真,取 b,否则取 c

常见用途(代替 if-else)

int maxv = (x > y) ? x : y;

等价于:

if (x > y) maxv = x;
else maxv = y;

易错点 1:嵌套三目可读性差

int ans = a > b ? (a > c ? a : c) : (b > c ? b : c);

虽然能用,但非常难读,建议改用 if

易错点 2:误把三目当“if语句”

三目是表达式,不是语句,必须有返回值。

❌ 错误:

a > b ? cout << a : cout << b;

虽然能编译,但不推荐(副作用写法)。

易错点 3:返回类型被“统一转换”

三目运算符结果类型会自动统一:

int x = (true ? 1 : 2.5);

结果是 1.0 → 再转 int → 1(可能发生隐式转换)

易错点 4:优先级坑

int x = a + b > c ? 1 : 0;

等价于:

int x = ((a + b) > c) ? 1 : 0;

但如果不加括号容易误读。

常见应用场景

  • 取最大 / 最小
  • 简单条件赋值
  • inline 表达式简化

三目运算符的嵌套

cout << ((mp[i][j] == 1) ? 1 : ((mp[i][j] == 3) ? 0 : 2)) << " ";
详细见洛谷6_1求细胞数量最后我自己的做法

一句话总结

三目运算符是表达式版 if-else”,能用就用简单情况复杂逻辑一定换 if

3. 整数转化为字符串

0~9可以通过
1. string s =char(1);
2. string s =1+'0';

Danger

但是这两种方法对于10以上的数字就会出问题,
string s =1+'0';本质上是 ASCII 码值的计算,而ASCII 码值没有11,12...诸如此类

错误代码

string s1 = i + '0';
错误原因 1. int + char 运算后结果为 int(ASCII 数值运算); 2. C++ 不支持 int 直接赋值给 string,类型不匹配编译报错; 3. i+'0' 仅适用于 0~9 单个数字,大数会乱码。

正确写法

to_string方法在头文件#include <string>

  1. 任意数字转字符串(推荐)
    string s1 = to_string(i);
    
  2. 单个数字 0~9 专用
    char c = i + '0';
    string s1 = c;
    
    核心口诀 数加字符变整数,整型不可赋字符串; 多位数字用to_string,单数字加零转字符。

4. memset()函数的使用

**C++ `memset` 知识卡片(简洁版)**

memset:按字节给一段内存批量赋值,常用于数组初始化。

#include <cstring>
memset(数组名, , 字节数);

常用写法

int a[100];
memset(a, 0, sizeof(a));     // 全部置 0
memset(a, -1, sizeof(a));    // 全部置 -1
memset(a, 0x3f, sizeof(a));  // 设为大整数(常作 INF)

为什么 memset(a,1,...) 不行?

因为它按字节填充:

01 01 01 01

一个 int 会变成:

16843009

不是 1

适用场景

int a[1000];
bool vis[1000];
char s[1000];
int mp[100][100];

数组清零、标记数组、二维数组初始化都很常用。

不适用场景

vector<int>
string
set / map
类对象

这些是对象类型,不要用 memset

Note

更安全的替代写法

fill(a, a+n, 1);

给数组赋非 0 / -1 值时,优先用 fill()

一句话记忆

memset 是按字节赋值。

所以:

0     最安全
-1    常用
0x3f  常作 INF
1~100 别乱给 int 数组用