Day04 郝斌C语言自学视频之C语言的流程控制

这篇笔记主要是介绍C语言中的第一个重点知识,流程控制,包括顺序、选择、循环等。阅读本文预计需要 30 分钟。

流程控制概述

流程控制是我们学习C语言的第一个重点,也是我们看懂程序的第一步,学习这部分后一定要能够熟练地分析一个程序代码的执行顺序。郝斌老师视频中讲解的非常详细,而且通俗易懂,如果某一部分理解有问题,可以多去看几遍郝斌老师的视频。

流程控制定义

流程控制是指程序代码的执行顺序。

流程控制的分类

流程控制基本分为顺序选择循环三种,其中顺序是最简单的,选择循环复杂一些。

顺序执行

顺序执行指按代码的先后顺序依次执行。

例1 顺序执行

/*
    时间:2020年2月21日10:00:07
    目的:
        测试顺序执行
*/

# include <stdio.h>

int main(void)
{
    printf("打印1\n");
    printf("打印2\n");
    printf("打印3\n");

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
打印1
打印2
打印3
--------------------------
*/

这里,代码依次打印1,2,3,就是按照顺序执行。顺序执行,比较好理解,这里不过多介绍。

选择执行

选择定义

选择执行指某些代码可能执行,也可能不执行。即有选择地去执行某些代码。

选择分类

选择执行主要分为if, if...else..., if...else if...else..., switch几种情况。重点是掌握if的相关用法,switch了解即可。

if 的用法

格式:
  if (表达式)
    语句A;
功能:
  如果表达式为真,则执行语句 A ,否则不执行语句 A

例2 if 的最简单用法

/*
    时间:2020年2月19日17:04
    目的:
        测试if的最简单用法
    总结:
        1. if后的表示式如果为真,则执行if后的第一个语句。
        2. if后的表示式如果为假,则不执行if后的第一个语句。
*/

# include <stdio.h>

int main(void)
{
    if (3 > 2)  // 为真
        printf("AAAA\n");  // 输出结果:AAAA
   
    if (3)  // 为真
        printf("BBBB\n");  // 输出结果:BBBB
   
    if (0)  // 为假
        printf("CCCC\n");  // 不会输出
   
    if (0 == 0)  // 为真
        printf("DDDD\n");  // 输出结果:DDDD

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
AAAA
BBBB
DDDD
--------------------------
*/

关于 if 的使用一定要注意其作用范围if 默认只能控制一个语句的执行或不执行,如果想控制多个语句的执行或不执行,那么就必须把这些语句用{}括起来。

说明 1:

if (表达式)
  语句A;
  语句B;

解释:if 默认只能控制语句 A 的执行或者不执行,无法控制语句 B 的执行或不执行。即:语句B一定会执行。所以这种时候,推荐写成如下格式,便于阅读:

if (表达式)
  语句A;
语句B;

如果想要 if 同时控制语句 A 和语句 B 则需要把语句 A 和语句 B{}括起来。

说明 2:

if (表达式)
{
  语句A;
  语句B;
}

解释:此时 if 可以控制语语句 A 和语句 B

if…else…的用法

格式:
  if (表达式)
    语句A;
  else
    语句B;
功能:
  如果表达式为真,则执行语句 A,否则执行语句 B

关于 ifelse 的使用一定要注意其作用范围ifelse 默认只能控制一个语句的执行或不执行,如果想控制多个语句的执行或不执行,那么就必须把这些语句用{}括起来。如:

格式:
  if (表达式)
  {
    语句A;
    语句B;
  }
  else
  {
    语句C;
    语句D;
  }

另外,else 前面必须有 if 成对,否则报错。

常见错误写法:
  if (表达式)
    语句A;
    语句B;
  else
    语句C;
解释:这样写法是错误的,因为语句 Belseif 隔断了,导致没有 ifelse 成对,

这种写法等价于:
  if (表达式)
    语句A;
  语句B;
  else
    语句C;

例3 if…else…的用法:

/*
    时间:2020年2月19日 17:33
    目的:
        测试if...else...的用法
    总结:
        1. if和else默认只能控制一个语句的执行或不执行。
        2. if和else要控制多个语句,则用{}把多个语句括起来。
        3. 注意非if和else控制的语句不要缩进。
*/

# include <stdio.h>

int main(void)
{
    int i, j;
   
    scanf("%d %d", &i, &j);  // 接受输入
   
    if (i > j)
        printf("i大于j\n");
    else
        printf("i小于j\n");

    printf("\n");  // 打印空行

    if (1 > 2)
        printf("AAAA\n");
        // printf("哈哈哈哈\n");  // 加了这行会报错,导致30行的 else 没有 if 配对
    else
        printf("BBBB\n");

    printf("CCCC\n");  // 注意代码规范,这行代码不要缩进

    return 0;
}

/*
    在VSCode中的输入输出结果是:
--------------------------
1 2
i小于j

BBBB
CCCC
--------------------------
*/

if…else if…else…的用法

格式:
  if (表达式1)
    语句A;
  else if (表达式2)
    语句B;
  else if (表达式3)
    语句C;
  else:
    语句D;
功能:
  如果表达式1成立,则执行语句 A;如果表达式2成立,则执行语句 B;如果表达式3成立,则执行语句 C;否则执行语句 D

关于 ifelse ifelse 的使用一定要注意其作用范围ifelse ifelse 默认只能控制一个语句的执行或不执行,如果想控制多个语句的执行或不执行,那么就必须把这些语句用{}括起来。

这里的注意事项和常见错误同 if...else... ,不再赘述。

例4 if…else if…else…的用法


/*
    时间:2020年2月19日 17:57
    目的:
        测试if...else if...else的用法
    总结:
        1. 注意if...else if ...else必须成对出现
        2. 警惕if...else if...else的作用范围导致的错误
*/

# include <stdio.h>

int main(void)
{
    double delta = 3;

    if (delta > 0)
        printf("有两个解!\n");
        // printf("哈哈!\n");  // 加了这句会报错,导致后面的else if语法错误
    else if (delta == 0)
        printf("有一个唯一解!\n");
    else
        printf("无解!\n");

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
有两个解!
--------------------------
*/

if 的常见问题解析

1. 空语句问题  
    if (3 > 2);    
    等价于 
    if (3 > 2) 
        ;  // 这是一个空语句   

2. if...else...    
    if (表达式)    
      语句A; 
    else:     
      语句B; 
    这是正确的。
    而:   

    if (表达式);  // 这里多了个 ';',形成了空语句  
      语句A; 
    else  // 这个 else 没有 if 配对    
        语句B; 
    是错误的。

3. if...else if...else
    if (表达式1)
        语句A;
    else if (表达式2)
        语句B;
    else if (表达式3)
        语句C;
    else
        语句D;
即便表达式1/2/3都成立,也只会执行A语句.

4.  if...else if...
    if (表达式1)
        语句A;
    else if (表达式2)
        语句B;
    else if (表达式3)
        语句C;
    这么写语法没有错,但是逻辑上有漏洞。

5. if...else if...else
    if (表达式1)
        语句A;
    else if (表达式2)
        语句B;
    else if (表达式3)
        语句C;
    else (表达式4)  // 7行
        语句D;
这样写是错误的,正确的写法是:
要么去掉7行的(表达式4);要么在7行的 else 后面加 if 。

6. if...else if...else
if (表达式1)
    语句A;
else if (表达式2)
    语句B;
else if (表达式3)
    语句C;
else (表达式4);  // 注意这里有个 ; ,跟5不一样
    语句D;
这样写语法不会出错,但逻辑上是错误的。
    else (表达式4);
        语句D;
    等价于
    else
        (表达式4);
    语句D;

switch 的用法

格式:
  switch (表达式)
  {
    case 常量表达式1: 语句1;
    case 常量表达式2: 语句2;
    default:       语句3;
    case 常量表达式3: 语句4;
  }

说明:

  1. 所有 case 后面的常量表达式,为便于描述我们姑且称之为标签,这些标签都只能是:1)枚举常量(有些书称之为枚举元素);2)数值常量;3)字符常量;4)常变量;5)宏名中的一种,注意普通变量,枚举变量是不能作为标签使用的。

  2. switch 后面括号里的表达式允许是任何类型。

  3. 执行完一个case语句后,流程控制就转移到下一个case子句继续执行,"case"常量表达式只是起语句标号的作用,并不是在该处进行条件判断。在执行switch语句时,根据switch()中的表达式的值找到与之匹配的case子句,就从此case子句开始执行下去,不再进行判断。即找到程序执行的入口后,就顺序执行剩下的代码

  4. switch 是选择不是循环,如果在 switch 中出现了 break 语句。该语句的功能知识退出 switch 语句转去执行它下面的语句。在 switch 中出现 continue 是错误的,除非 switch 本身就属于 forwhile 循环的一部分。

例5 switch 的用法

/*
    时间:2020年2月20日15:13:55
    功能:
        测试switch的用法,电梯程序
    总结:
        1. switch就是找程序的入口,找到后就顺序执行剩余的代码。
*/

# include <stdio.h>

int main(void)
{
    int val;

    printf("请输入您要进入的楼层:");
    scanf("%d", &val);

    switch (val)
    {
        case 1:
            printf("1层开!\n");
            // break;
        case 2:
            printf("2层开!\n");
            // break;
       case 3:
            printf("3层开!\n");
            // break;
        default:
            printf("还没有盖到这一层!\n");
    }

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
请输入您要进入的楼层:1
1层开!
2层开!
3层开!
还没有盖到这一层!
--------------------------
*/

循环执行

循环定义

循环是指某些代码会被重复执行。循环的创造是为了把一些规律性的操作,通过几行循环代码解决,避免我们输入冗余的代码,提升开发效率,使得代码更加简洁。

循环分类

循环语句主要有 forwhiledo...while,三种,其中 forwhile 是用的最多的,do...while 主要用于人机交互。

forwhile 可能一次循环都不执行,而do...while 至少执行一次循环。

单个 for 循环的用法

格式:
  for (1; 2; 3)
    A;
功能:
  先执行 1 ,然后执行条件判断语句 2。如果 2 成立,则依次执行语句 A3,再执行2,以此循环。如果 2 不成立,则循环结束,不再继续执行 A3。注意:1 永远只执行一次。

例6 单个 for 循环的用法

/*
    时间:2020年2月20日09:48:37
    功能:
        for循环求1-100之间所有奇数之和
    总结:
        1. for 的默认作用范围是一个语句。
        2. for 作用于多个语句,需要使用 {} 把多个语句括起来
*/

# include <stdio.h>

int main(void)
{
    int i;
    int sum = 0;

    for (i=1; i<100; i+=2)  // i+=2 等价于 i = i + 2
    {
        sum += i;  // 等价于 sum = sum + i;
    }
   
    printf("i = %d, sum = %d\n", i, sum);
   
    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
i = 101, sum = 2500
--------------------------
*/

关于单个 for 的使用也一定要注意其作用范围for 默认只能控制一个语句的循环或不循环,如果想控制多个语句的循环或不循环,那么就必须把这些语句用{}括起来。

这里的注意事项和常见错误同 if 类似,不再赘述。

多个 for 循环的嵌套使用

格式 1:
  for (1; 2; 3) // 1
    for (4; 5; 6) // 2
      A; // 3
  B; // 4
功能:
  多个 for 循环嵌套,从最外面的循环开始执行,先执行 1 ,再执行条件判断语句 2。如果 2 成立,则依次执行语句 4 和 5,如果 5 成立 则执行 A和 6,如果 5不成立,则结束第二个 for 循环,去执行3,再执行2,以此循环。直到 2 为假时,结束循环。(这里有点绕,详细的请看郝斌老师视频,讲解非常细)

这里整体算两个语句,1 2 3 行是第一个语句,4 行是第2个语句。

格式 2:
  for (1; 2; 3)
    for (4; 5; 6)
    {
      A;
      B;
    }
整体是一个语句。可能执行顺序:1 2 4 5 A B 6 5 3 2 (每个循环只执行一次)

格式 3:
  for (1; 2; 3)
    for (4; 5; 6)
    {
      A;
      B;
      for (7; 8; 9)
        C;
    }
整体是一个语句。可能执行顺序:1 2 4 5 A B 7 8 C 9 8 6 5 3 2 (每个循环只执行一次)

关于多个 for 的嵌套使用更要注意其作用范围for 默认只能控制一个语句的循环或不循环,如果想控制多个语句的循环或不循环,那么就必须把这些语句用{}括起来,推荐一个语句也用花括号{}

例7 多个 for 循环的嵌套的用法

/*
    时间:2020年2月20日12:55:12
    目的:
        多个for嵌套使用案例
    总结:
        1. 多个 for 嵌套注意范围问题
*/

# include <stdio.h>

int main(void)
{
    int i, j;

    for (i=0; i<3; ++i)
        // printf("嘿嘿!\n");  // 例子2
        for (j=2; j<5; ++j)
            printf("哈哈!\n");
        // printf("嘻嘻!\n");  // 不推荐这么写
    printf("嘻嘻!\n");  // 推荐

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
哈哈!
哈哈!
哈哈!
哈哈!
哈哈!
哈哈!
哈哈!
哈哈!
哈哈!
嘻嘻!
--------------------------
*/

for 和 if 嵌套使用

for 和 if 可以组合使用。

例8 for 和 if 嵌套的用法

/*
    时间:2020年2月20日10:52:45
    功能:
        求1-100之间的奇数之和
        求1-100之间的奇数个数
        求1-100之间的奇数平均值
        求1-100之间的奇数之和,再求1-100之间的偶数之和
*/

# include <stdio.h>

int main(void)
{
    int i;  // 循环变量
    int sum_odd = 0;  // 奇数之和
    int sum_even = 0;  // 偶数之和
    int cnt = 0;  // 奇数的个数,个数一般用cnt表示
    float average_odd = 0;  // 奇数的平均值

    for (i=1; i<=100; ++i)
    {
        if (i%2 == 0)
        {
            sum_even += i;  // 等价于 sum_even = sum_even + i;
        }
        else
        {
            sum_odd += i;  // 等价于 sum_odd = sum_odd + i;
            ++ cnt;  // 等价于 cnt = cnt + 1;
        }
    }

    average_odd = 1.0*sum_odd / cnt;  // 推荐这么写,1.0 默认是double类型
    // average_odd = sum_odd / (float)(cnt);  // 不推荐这么写

    printf("1-100之间的奇数之和是:%d\n", sum_odd);
    printf("1-100之间的奇数个数是:%d\n", cnt);
    printf("1-100之间的奇数平均值:%f\n", average_odd);  // 这里是%f
    printf("1-100之间的奇数之和是:%d, 偶数之和是:%d\n", sum_odd, sum_even);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
1-100之间的奇数之和是:2500
1-100之间的奇数个数是:50
1-100之间的奇数平均值:50.000000
1-100之间的奇数之和是:2500, 偶数之和是:2550
--------------------------
*/

while 循环的用法

while和for可以相互转换,但for逻辑性更强,更不容易出错,推荐多使用for。

格式:
  while (表达式)
    A;
功能:
  表达式为真时,执行语句 A, 直到表达式为假,结束循环。

while 和 for 互换,如下:
for (1; 2; 3)
  A;
等价于
1;
while (2)
{
  A;
  3;
}

关于 while 的使用也要注意其作用范围while 默认只能控制一个语句的循环或不循环,如果想控制多个语句的循环或不循环,那么就必须把这些语句用{}括起来,推荐一个语句也用花括号{}

例9 while Vs for 循环的用法

/*
    时间:2020年2月20日13:41:31
    功能:
        求 1 + 2 + 3 + ... + 100 的和
    目的:
        比较 for 和 while 的异同
    总结:
        1. for和while可以互相转换。
        2. for逻辑性更强,更不易出错,推荐使用。
*/

# include <stdio.h>

int main(void)
{
    int i;
    int j;
    int sum_1 = 0;  // for求和
    int sum_2 = 0;  // while求和

    for (i=1; i<101; ++i)
    {
        sum_1 += i;
    }
    printf("sum_1 = %d\n", sum_1);

    j = 1;
    while (j<101)
    {
        sum_2 += j;
        ++j;
    }
    printf("sum_2 = %d\n", sum_2);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
sum_1 = 5050
sum_2 = 5050
--------------------------
*/

do…while 循环的用法

do...while 循环格式:
  do
  {
    A;
    B;
  } while (表达式)
功能:
  先执行 do {} 中的语句 AB ,再执行 while 表达式,如果表达式成立,则继续执行 do {},否则结束循环,即循环体至少会执行 1 次。

while 循环格式:
  while (表达式)
  {
    A;
    B;
  }

for 循环格式:
  for (1; 2; 3)
  {
    A;
    B;
  }

注意:do...while 并不等价于 for,当然也不等价于 while
主要是用于人机交互。

例10 do...while 循环的用法

/*
    时间:2020年2月20日14:48:36
    功能:
        用 do...while 实现一元二次方程
    总结:
        1. do...while主要是便于人机交互。
        2. do...while至少会执行一次循环,while和for可能一次循环都不执行。
        3. scanf()输入%c时,一定要在%c前保留一个空格
*/

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a, b, c;
    double delta;
    double x1, x2;
    char ch;

    do
    {
        printf("请输入一元二次方程的三个系数:\n");
        printf("a = ");
        scanf("%lf", &a);

        printf("b = ");
        scanf("%lf", &b);

        printf("c = ");
        scanf("%lf", &c);

        delta = b * b - 4 * a * c;

        if (delta > 0)
        {
            x1 = (-b + sqrt(delta)) / (2 * a);
            x2 = (-b - sqrt(delta)) / (2 * a);
            printf("该一元二次方程有两个解,x1 = %lf,x2 = %lf\n", x1, x2);
        }
        else if (delta == 0)
        {
            x1 = x2 = (-b) / (2 * a);
            printf("该一元二次方程有唯一解,x1 = x2 = %lf\n", x1, x2);
        }
        else
        {
            printf("该一元二次方程无实数解!\n");
        }
        printf("您想继续吗(Y/N):");
        scanf(" %c", &ch);  // %c前面必须得加一个空格 原因略
        // scanf("%c", &ch);  // 错误写法,程序直接跳出循环
    } while ('Y'==ch || 'y'==ch);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
请输入一元二次方程的三个系数:
a = 1
b = 2
c = 3
该一元二次方程无实数解!
您想继续吗(Y/N):y
请输入一元二次方程的三个系数:
a = 3
b = 4
c = 5
该一元二次方程无实数解!
您想继续吗(Y/N):N
--------------------------
*/

break 的用法

break 有 3 种用法:

  1. break 如果用于循环是用来终止循环,并且是距离它最近的一个循环。

  2. break 如果用于switch,则是用来终止switch。

  3. break 不能直接用于if,除非if属于循环内部的一个子句。

这里主要放出一些 break 使用情况的代码片段:

例11 break 的用法1

/*
    时间:2020年2月20日16:27:18
    目的:
        测试 break 的用法
    总结:
        break 只能终止距离它最近的循环
*/

# include <stdio.h>

int main(void)
{
    int i, j;

    for (i=0; i<3; ++i)  // 第 1 个 for 循环
    {
        for (j=1; j<4; ++j)  // 第 2 个 for 循环
            break;  // break 只能终止距离它最近的循环,即 第 2 个 for
        printf("同志们好!\n");
    }

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
同志们好!
同志们好!
同志们好!
--------------------------
*/

例12 break 的用法2

/*
    时间:2020年2月20日16:43:56
    目的:
        测试 break 在多层嵌套 switch 中的用法
    总结:
        1. 在多层switch嵌套中,break 只能够终止距离它最近的switch。
*/

# include <stdio.h>

int main(void)
{
    int x=1, y=0, a=0, b=0;

    switch(x)  // 第一个 switch
    {
        case 1:
            switch(y)  // 第二个switch
            {
                case 0:
                    a++;
                    break;  // 终止的是第二个switch
                case 1:
                    b++;
                    break;  // 终止的是第二个switch
            }
            b = 100;
            break;  // 终止的是第一个switch
        case 2:
            a++;
            b++;
            break;  // 终止的是第一个switch
    }

    printf("a = %d, b = %d\n", a, b);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
a = 1, b = 100
--------------------------
*/

例13 break 的用法3

/*
    时间:2020年2月20日16:16:26
    目的:
        测试 break 的用法
    总结:
        break 虽然是if内部的语句,但break终止的的确是外部的for循环
*/

#include <stdio.h>

int main(void)
{
    int i;

    switch (2)
    {
    case 2:
        printf("哈哈!\n");
        break; // OK,break 可以用于switch

    default:
        break;
    }

    for (i = 0; i < 3; ++i)
    {
        if (3 > 2)
            break;  // break 虽然是if内部的语句,但break终止的的确是外部的for循环
        printf("嘿嘿!\n");  // 永远不会输出
    }
    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
哈哈!
--------------------------
*/

continue 的用法

用于跳过本次循环余下的语句,转去判断是否需要执行下次循环。

  1. continuefor 循环中的使用:
    for (1; 2; 3)
    {
        A;
        B;
        continue;  // 如果执行该语句,则执行完该语句后,会执行语句3,跳过 C 和 D
        C;
        D;
    }

如果执行 continue,则执行完 continue 后,会执行语句 3 ,跳过 C 和 D,去执行 3 和 2。

  1. continuewhile 循环中的使用
    while (表达式)
    {
        A;
        B;
        continue;  // 如果执行该语句,则执行完该语句后,会执行表达式,跳过 C 和 D
        C;
        D;
    }

如果执行 continue,则执行完 continue 后,会执行语句 3 ,跳过 C 和 D,去执行表达式。

其他琐碎知识

C 语言对真假的处理

非 0 是真
0 就是假
真用 1 表示
假用 0 表示

如何学习一些需要算法的程序【如何掌握一个程序】

这也是刷算法题的心得。

  1. 尝试自己去编程解决它,但要意识到大部分人都是自己无法解决的,这时不要气馁,如果10分钟还想不出来,就看答案。

  2. 如果解决不了,就看答案。关键是把答案看懂,这个要花很大精力,也是我们学习的重点。看懂一个程序要分三步:流程、每个语句的功能、试数。

  3. 看懂之后尝试自己去修改程序,并且知道修改之后程序的输出结果的含义。
    不建议看懂程序之后就立即自己敲程序。

  4. 照着答案去敲。

  5. 调试错误。

  6. 不看答案,自己独立把答案敲出来。

  7. 如果程序实在无法彻底理解,就把它背会,这种情况极少见。

进制

进制目前需要弄懂以下四个问题:

  1. 什么叫n进制?即:逢n进一。

  2. 把r进制转成十进制。即:从左到右依次把数字乘以r对应的幂指数。

  3. 十进制转成r进制。方法:除r取余,直至商0,余数倒序排列。

  4. 不同进制所代表的的数值之间的关系。十进制的 3981 转化为十六进制是 F8D。十进制的 3981 和 十六进制的 F8D 所代表的本质上都是同一个数

补充一些琐碎运算符知识

运算符 表达式 说明
前自增 ++i 使得变量 i 的值 +1
后自增 i++ 使得变量 i 的值 +1
前自减 –i 使得变量 i 的值 -1
后自减 i– 使得变量 i 的值 -1
三目运算符 i = A ? B : C 若 A 真,则 i = B; 否则 i = C
逗号表达式 (A, B, C, D) i = (3, 2, 5, 6); i 最后等于 6

自增

设计自增和自减的可能原因:

  1. 代码更加精炼。

  2. 自增的速度更快。

比较前后自增的异同

前自增 后自增
表达式 ++i –i
相同 都使 i 的值 +1 都使 i 的值 +1
不同 ++i 整体表达式的值是i加1之后的值 i++ 后自增整体表达式的值是i加1之前的值

学习自增要明白的几个问题:

  1. 编程时应该尽量不要体现自增和自减的区别。或者说编程时尽量屏蔽掉前后自增和自减的差别。

  2. i++ 和 ++i 单独成一个语句,不要把它作为一个完成复合语句的一部分来使用。或者说,自增表达式最好不要作为一个更大的表达式的一部分来使用。

如:写成 int m = i++ + ++i + i + i++; 这么写,不但是不规范的代码,而且是不可移植的代码。不可移植是因为,不同机器上对于这个语句的执行顺序有区别。顺序点有三个 ,() 以及 ;printf("%d %d %d", i++, ++i, i); 也是不推荐,原因同上。

例14 前后自增的用法

/*
    时间:2020年2月20日12:22:24
    目的:
        前后自增的异同
    总结:
        前自增和后自增的异同:
        相同:
            最终都是使i的值加1.
        不同:
            前自增整体表达式的值是i加1之后的值。
            后自增整体表达式的值是i加1之前的值。
*/

# include <stdio.h>

int main(void)
{
    int i, j, k, m;

    i = j = 3;  // 等价于 i = 3; j = 3;
    k = i++;
    m = ++j;

    printf("i = %d, j = %d, k = %d, m = %d\n", i, j, k, m);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
i = 4, j = 4, k = 3, m = 4
--------------------------
*/

自减同自增,不再赘述。

三目运算符

格式:
  A ? B : C
等价于
  if (A)
    B;
  else
    C;
功能:
  如果 A 为真,则执行 B ,否则执行 C。

例15 三目运算符的用法

/*
    时间:2020年2月20日12:39:31
    目的:
        测试三目运算符
    总结:
        A ? B : C
        等价于
            if (A)
                B;
            else
                C;
*/

# include <stdio.h>

int main(void)
{
    int i;

    i = (3>2 ? 5 : 1);

    printf("i = %d\n", i);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
i = 5
--------------------------
*/

逗号表达式

格式:
  (A, B, C, D)
功能:
  从左到右执行,最终表达式的值是最后一项的值。

例16 逗号表达式的用法

/*
    时间:2020年2月20日12:44:01
    目的:
        测试逗号表达式用法
    总结:
        1. 从左到右执行,最终表达式的值是最后一项的值。
*/

# include <stdio.h>

int main(void)
{
    int i;
    int j = 2;

    i = (3, 2, 5, 6);
    printf("i = %d\n", i);
    i = (j++, ++j, j+2, j-3);  // 不要这么写,这里是为了测试
    printf("i = %d\n", i);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
i = 6
i = 1
--------------------------
*/

强制类型转换

格式:
  (数据类型)(表达式)
功能:
  把表达式的值强制转化为前面所执行的数据类型。

如:

表达式 结果
(int)(4.5+2.2) 6
(float)(5) 5.000000

能不用强制类型转换就不用,使用灵活的方法替换。

例17 强制类型转换的用法

/*
    2020年2月20日10:13:40
    功能:
        求1 + 1/2 + 1/3 + ... + 1/100之和
    总结:
        1. 能不用强制类型转换就不用,使用灵活的方法替换
*/

# include <stdio.h>

int main(void)
{
    int i;
    float sum = 0;

    for (i=1; i<=100; ++i)
    {
        sum = sum + 1.0/i;  // 是OK的,推荐使用
        // sum = sum + (float)(1/i);  // 这样写是不对的
        // sum = sum + 1 / (float)(i);  // 这样写也可以,不过不推荐使用
    }

    printf("sum = %f\n", sum);  // float 必须用%f输出

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
sum = 5.187378
--------------------------
*/

试数

原则:把自己当计算机,严格按照计算机的顺序执行。也可以通过断点调试,一步一步看程序执行的过程。

浮点数存储所带来的问题

floatdouble 都不能保证可以精确地存储一个小数。
题目:有一个浮点型的变量x,如何判断x的值是否是0.

// 解法一,这是伪代码
    if (0 == x)0
    else
        不是0
// 这种解法是错误的
// 解法二,这是伪代码
    if (|x-0.000001| <= 0.000001)0
    else
        不是0
    // 这种解法才是正确

另外,循环更新的变量不能定义为浮点型,以免发生不可预测的错误。

例18 循环更新变量的错误用法

/*
    时间:2020年2月20日10:48:42
    总结:
        1. 本程序不对,因为循环中更新的变量不能定义为浮点型
*/

# include <stdio.h>

int main(void)
{
    float i;
    float sum = 0;

    for (i=1.0; i<=100; ++i)
    {
        sum = sum + 1/i;
    }

    printf("sum = %f\n", sum);

    return 0;
}

/*
    在VSCode中的输出结果是:
--------------------------
sum = 5.187378
--------------------------
*/

说明

  1. 本学习笔记整理自B站郝斌老师的《郝斌C语言自学教程》片段P47-P96

  2. 笔记中所有代码均在windows10操作系统,在VSCode编辑器中通过测试。具体VSCode C语言开发环境搭建方法请参照我的另一篇CSDN博客——Windows10下利用Visual Studio Code搭建C语言开发环境

后记

如果对你有所帮助,欢迎关注我的这个公众号。这个公众号主要是慢慢分享和记录自己学习编程的笔记,比如:C,Python,Java等,后续也会分享自己面试以及在职场上的成长心得。
在这里插入图片描述

发布了128 篇原创文章 · 获赞 157 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_27283619/article/details/104534028