if (op == ‘I’) op 是什么意思
*op == 'I'
的意思是 取 op
的第一个字符,并判断它是否等于 'I'
。
详细解释:
op
的定义:
cpp char op[2]; // 定义一个长度为2的字符数组
op
是一个字符数组,用于存储用户输入的操作类型(如"I"
或"Q"
)。-
由于
scanf("%s", op)
读取字符串时,会自动在末尾添加'\0'
(字符串结束符),所以op
至少需要2
个空间:- 第1个字符存储操作类型(
'I'
或'Q'
)。 - 第2个字符存储
'\0'
(表示字符串结束)。
- 第1个字符存储操作类型(
-
*op
的含义: op
是数组名,在C/C++中,数组名代表数组的首地址。*op
等价于op[0]
,即取op
的第一个字符。-
因此,
*op == 'I'
就是检查op
的第一个字符是否是'I'
。 -
为什么不用
op == "I"
? "I"
是一个字符串(包含'I'
和'\0'
),而op
也是一个字符串。- 在C/C++中,直接比较
op == "I"
是比较两个指针(地址),而不是字符串内容。 -
正确的字符串比较应该用
strcmp(op, "I") == 0
,但这里只需要比较第一个字符,所以*op == 'I'
更高效。 -
示例:
- 如果用户输入
I abc
:op
存储"I"
(即op[0] = 'I'
,op[1] = '\0'
)。*op
就是'I'
,所以*op == 'I'
成立,执行插入操作。
- 如果用户输入
Q abc
:op
存储"Q"
(即op[0] = 'Q'
,op[1] = '\0'
)。*op
就是'Q'
,所以*op == 'I'
不成立,执行查询操作。
总结
*op
是op[0]
的简写,表示op
字符串的第一个字符。*op == 'I'
用于判断用户输入的操作是否是'I'
(插入操作)。- 这种写法比
strcmp
更高效,因为只需要比较一个字符。
scanf(“%s%s”, op, str);为什么这个op,str前面不能加&
在C语言中,scanf
用于读取输入数据时,对于不同类型的变量,传参方式有所不同:
1. 为什么 op
和 str
前面不需要加 &
?
op
和str
都是 字符数组(char[]
):
c char op[2]; // 存储操作类型(如 "I" 或 "Q") char str[N]; // 存储输入的字符串(如 "abc")
- 数组名本身就代表数组的首地址,所以直接传
op
或str
就相当于传入了它们的地址,不需要额外加&
。
2. 什么时候需要加 &
?
&
是取地址运算符,用于获取变量的内存地址。在 scanf
中:
- 基本类型(如 int
, float
, char
) 需要加 &
:
c
int n;
scanf("%d", &n); // n 是 int,必须加 & 取地址
- 数组类型(如 char[]
) 不需要加 &
,因为数组名本身就是地址:
c
char name[100];
scanf("%s", name); // name 是 char[],不加 &
3. 为什么 char[]
不加 &
?
- 在C语言中,数组名会自动转换为指向数组首元素的指针(即
&name[0]
)。 - 所以
scanf("%s", name)
等价于:
c scanf("%s", &name[0]); // 但一般不这么写,直接写 name 更简洁
- 如果错误地加了
&
:
c scanf("%s", &name); // 语法正确,但风格不好(`&name` 和 `name` 值相同,但类型不同)
虽然能运行,但不符合常规写法,容易引起误解。
4. 特殊情况:char*
(指针)
如果 str
是动态分配的 char*
,仍然不需要加 &
:
char* str = malloc(100 * sizeof(char));
scanf("%s", str); // 不加 &,因为 str 已经是指针
5. 总结
变量类型 | scanf 写法 |
原因 |
---|---|---|
int n |
scanf("%d", &n); |
n 是普通变量,需要取地址 |
char str[N] |
scanf("%s", str); |
str 是数组,自动转地址 |
char* p |
scanf("%s", p); |
p 已经是指针,无需 & |
关键点
✅ 数组名就是地址,所以 char[]
在 scanf
中不需要 &
。
✅ 普通变量(如 int
, char
) 需要 &
取地址。
❌ 错误写法:scanf("%s", &str);
(虽然能运行,但不推荐)。
这种设计是为了让数组的使用更直观,减少代码冗余。
if(!son[p][u]) return 0; p = son[p][u]; 为什么这个不用else
在 query
函数中,if (!son[p][u]) return 0;
后面直接跟 p = son[p][u];
而不使用 else
,是因为 return
语句已经终止了当前函数的执行,所以如果 son[p][u]
不存在,程序会直接返回 0
,不会执行后面的 p = son[p][u];
。
代码逻辑分析
int query(char *str) {
int p = 0;
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (!son[p][u]) return 0; // 如果子节点不存在,直接返回0(终止函数)
p = son[p][u]; // 否则继续向下移动(不会执行到这一步如果已经return)
}
return cnt[p];
}
为什么不需要 else
?
return
的作用:return 0;
会立即结束query
函数的执行,并返回0
。-
如果
son[p][u]
不存在,程序不会继续执行p = son[p][u];
,所以不需要else
。 -
如果
son[p][u]
存在: if (!son[p][u])
条件不成立,跳过return 0;
。- 继续执行
p = son[p][u];
,移动到子节点。
对比 if-else
写法
如果非要加 else
,可以写成:
if (!son[p][u]) {
return 0;
} else {
p = son[p][u];
}
但这样会多一层缩进,代码不够简洁。原写法更高效,因为 return
已经确保了后续代码不会执行。
总结
return
语句会终止函数执行,所以if
之后不需要else
。- 这种写法更简洁,是C/C++中的常见优化方式。
- 适用于提前返回(early return)的情况,可以减少嵌套层次,提高代码可读性。