1 三目运算符
1.1 三目运算符初探
三目运算符 (a ? b : c) 可以作为逻辑运算的载体
规则:当 a 的值为真时,返回 b 的值,否则返回 c 的值
下面看一下例子,初识三目运算符?
例子:三目运算符初探
// 18-1.c
#include<stdio.h>
int main()
{
int a = 1;
int b = 2;
int c = 0;
c = a < b ? a : b;
(a < b ? a : b) = 3;
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
编译器报错,不能操作左值,其实编译器返回变量的值,不会返回变量本身。
(a < b ? a : b) = 3 ==> 1 = 3,这是不合法的
如何修改呢,我们让三目运算符返回变量的地址就可以了,可以根据地址修改变量的值,修改如下:
// 18-1.c
#include<stdio.h>
int main()
{
int a = 1;
int b = 2;
int c = 0;
c = a < b ? a : b;
*(a < b ? &a : &b) = 3;
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
c = a < b ? a : b;
相当于:
if(a < b) c = a;
else c = b;
1.2 三目运算符的返回类型
三目运算符(a ? b : c)的返回类型:
- 通过隐式类型转换规则返回 b 和 c 中的较高类型
- 当 b 和 c 不能隐式转换到同一类型时将编译报错
下面看一个例子,查看三目运算符的返回类型
// 18-2.c
#include<stdio.h>
int main(){
char c = 0;
short s = 0;
int i = 0;
double d = 0;
char* p = "str";
printf("%ld\n", sizeof(c ? c : s));
printf("%ld\n", sizeof(i ? i : d));
printf("%ld\n", sizeof(d ? d : p));
return 0;
}
我们先来分析一下:
1、变量 c 和 s 的较高类型是 int,所以 c ? c : s 返回类型为 int,大小为 4字节。
2、变量 i 为 int 类型,i 4字节;变量 d 为 double,8字节空间,i ? i : d 返回类型为 double,大小为 8 字节
3、p 为 char 类型的指针,不能 double 类型转换到同一类型,编辑将报错。
真的是这样吗?我们编译一下:
编译器提示,d 和 p 类型不匹配,和我们分析的一样。注释第 11 行,再次编译:
结果和我们分析的完全一致。
2 逗号表达式
- 逗号表达式是 C 语言中的”粘贴剂“,用于将多个子表达式连接为一个表达式
- 逗号表达式的值为最后一个子表达式的值
- 逗号表达式中的前 N-1 个子表达式可以没有返回值
- 逗号表达式按照从左向右的顺序计算每个子表达式的值
下面看一个逗号表达式的示例:
// 18-3.c
#include<stdio.h>
void hello(){
printf("Hello!\n");
}
int main(){
int a[3][3] = {
(0, 1, 2),
(3, 4, 5),
(6, 7, 8)
};
int i = 0;
int j = 0;
while(i < 5)
printf("i = %d\n", i),
hello(),
i++;
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
printf("a[%d][%d] = %d ", i, j, a[i][j]);
}
printf("\n");
}
return 0;
}
- 为什么while 循环执行 5 次而不是死循环呢,因为使用了逗号表达式,printf(“i = %d\n”, i), hello(), i++; 是一个表达式。
- 为什么矩阵中元素,前三个是 2,5,8,后面的都是 0 呢,同样的,(0, 1, 2) 和 (3, 4, 5) 和 (6, 7, 8) 都是逗号表达式,其值等于最后一个子表达式的值,所以 int a[3][3] = { (0, 1, 2), (3, 4, 5), (6, 7, 8) }; 相当于 int a[3][3] = { 2, 5, 8 };
最后我们来做一个题:一行代码实现 strlen
// 18-4.c
#include<stdio.h>
#include<assert.h>
int mystrlen(const char* s)
{
return assert(s), (*s ? mystrlen(s+1)+1 : 0);
}
int main()
{
printf("len = %d\n", mystrlen("hello"));
printf("len = %d\n", mystrlen(NULL));
return 0;
}
利用逗号表达式将 assert(s) 和 (*s ? mystrlen(s+1)+1 : 0) 连接起来,成为一个表达式,为什么需要 assert(s) 呢,因为如果 s 为空,对 s 解引用会出错。
编译运行,结果如下:
3 小结
1、三目运算符返回变量的值,而不是变量本身
2、三目运算符通过隐式类型转换规则确定返回值类型
3、逗号表达式按照从左向右的顺序计算每个子表达式的值,其值等于最后一个子表达式的值