++和--操作符分析 好

1. ++和—操作符对应的两条汇编指令

(1)前置++或--:变量自增(减)1,然后取变量值

(2)后置++或--:取变量值,然后变量自增(减)1

【实例分析】一对令人头疼的兄弟

#include <stdio.h>

int main()
{
    int i = 0;
    int r = 0;

    r = (i++) + (i++) + (i++);

    printf("i = %d\n", i); //i等于3
    printf("r = %d\n", r); //vc下r=0,gcc也等于0

    r = (++i) + (++i) + (++i);

    printf("i = %d\n", i); //i等于6
    printf("r = %d\n", r); //vc下r=18 即(6+6+6),gcc下等于16 (5+5+6),java下等于15;
    return 0;
}

2. C标准对++和—运算符的规定

(1)C语言中只规定了++和—对应指令的相对执行次序(即两条汇编指令的前后顺序是有规定的,但不一定要紧紧相邻!

(2)但他们的汇编指令不一定连续运行,在混合运算中,其汇编指令可能被打断执行。(即上述两条汇编指令中间可能会被其他指令穿插进来,从而导致这两条指令不能连续、紧凑地执行)。

  ++和—参与混合运算,结果是不确定的。

3. 头疼的兄弟与逗号表达式

int x;
int i;
x = (++i, i++, i+10); //x=15

4. 逗号表达式:exp1,exp2,epx3,…,expN;

(1)逗号表达式是C语言中的“粘贴剂”

(2)逗号表达式用于将多个子表达式连接为一个表达式

(3)逗号表达式的值为最后一个子表达式的值

(4)逗号表达式中的前N-1个子表达式可以没有返回值

(5)逗号表达式按照从左向右的顺序计算每个子表达式的值

【实例分析】逗号表达式的示例

#include <stdio.h>

void hello()
{
    printf("Hello!\n");
}

int main()
{
    int a[3][3] = {
        (0, 1, 2), //注意是逗号表达式,不是{0,1,2}。相当于a[0]=2;
        (3, 4, 5), //注意是逗号表达式,不是{3,4,5}。相当于a[1]=5;
        (6, 7, 8)  //注意是逗号表达式,不是{3,4,5}。相当于a[1]=8;
    };

    //int a[3][3] = {
    //    { 0, 1, 2 }, //是大括号,相当于a[0]=0,a[1]=1,a[2]=2,以此类推!
    //    { 3, 4, 5 }, 
    //    { 6, 7, 8 }  
    //};
    int i = 0;
    int j = 0;

    //注意,以下是逗号表达式,以下会出现死循环吗?
    //答案是:不会!因为以下语句相当于
    //while (i<5)
    //    printf("i=%d\n",i),hello(),i++;
    //而对于while语句来讲,循环体是分号结束(而不是逗号)
    //所以相当于加了大括号:{printf("i=%d\n",i),hello(),i++;}
    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\n", i, j, a[i][j]);
        }
    }

    return 0;
}

【编程实验】一行代码实现strlen

#include <stdio.h>
#include <assert.h>

//一行代码实现strlen
int strlen(const char*s)
{
    return assert(s), (*s ? strlen(s + 1) + 1 : 0);
}

int main()
{
    printf("len = %d\n", strlen("Hello World!\n")); //len=13;
    printf("len = %d\n", strlen(NULL)); //传入空指针,会断言失败!
    return 0;
}

5.笔试面试中的“奇葩”题

++i+++i+++i

是哪一种呢?,将涉及到C语言中的贪心法准则。

6. 贪心法:++、--表达式的阅读技巧

(1)编译器处理的每个符号应该尽可能多的包含字符

(2)编译器从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一下字符。

(3)重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。

(4)空格可以作为C语言中一个完整符号的休止符,当编译器读入空格后立即对之前读入的符号进行处理。

  理解贪心法的关键:当读取的字符串还是一个有意义的符号(或表达式时)并不会停止读入,而是继续读入下一个字符,直至完全不再可能组成一个有意义的符号为止。

【实例分析】贪心法阅读示例

#include <stdio.h>

int main()
{
    int i = 0;

    //处理过程:读入第1个字符+,加号是有意义的,因为他可以与其他符号再组成(如组成++
    //或加另一个变量,因此读取并不会停止),于是继续读入第2个字符+,编译器发现是
    //一个自增运算符,会继续读入后面的变量i,得++i。这时这个符号仍是有意义的。
    //但根据贪心法,还会再读入一个字符,即++i+,表示++i后面
    //会加上一个数,这也是有意义的。所以会再读入第5个字符,这里发现己经读入的字符串
    //己经不再可能变成一个有意义符号。所以会停止读入字符转向去处理之前读读入的这个子
    //表达式,这时会先++i,即得到1,然后++,即1++,所以便会出错。
    int j = ++i+++i+++i;

    int a = 1;
    int b = 4;
    int c = a+++ b; //读到a++是有意义的,会再读入一个字符+,仍有意义,会再次读入b,即(a++) + b

    int* p = &a;

    b = b/*p; //读到“b/”是有意义的,因为b可以去除一个数。所以会继续读到b/*,这时发现这个
              //字符串不可能再任何意义了,所以停止读取。但b/*这个表达式是非法的,所以编译器
              //会报错。同时/*会组成多行注释的开始,所以编译会把/*会面的内容当成注意的内容。
// 可以增加空格来处理,即 b = b / *p;
printf("i = %d\n", i); printf("j = %d\n", j); printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); return 0; }

7. 小结

(1)++和—操作符在混合运算中的行为可能不同

(2)编译器通过贪心法处理表达式中的子表达式

(3)空格可以作为C语言中一个完整符号的休止符

(4)编译器读入空格后立即对之前读入的符号进行处理。

(5)逗号表达式按照从左向右的顺序计算每个子表达式的值

(6)逗号表达式的值为最后一个子表达式的值

posted on 2018-04-16 14:12  arabain  阅读(119)  评论(0)    收藏  举报

导航