【C语言进阶剖析】18、三目运算符和逗号表达式

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、逗号表达式按照从左向右的顺序计算每个子表达式的值,其值等于最后一个子表达式的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值