《解锁编程核心技能:从青铜到王者的C语言分支循环完全训练手册》下

 6. while循环

在 C 语言的编程世界里,循环语句是实现程序自动化和高效执行的关键工具。C 语言为我们提供了 3 种强大的循环语句,而 while 循环就是其中一颗耀眼的“明星”。接下来,就让我们一同深入探索 while 语句的奥秘。

6.1 if 和 while 的对比

if 语句和 while 语句在语法结构上有着惊人的相似之处,就像是一对“双胞胎兄弟”。让我们先来看看它们的基本语法形式:

if(表达式)
 语句;
 
 
while(表达式)
 语句;//如果循环体想包含更多的语句,可以加上⼤括号

对比一下

#include <stdio.h>
int main()
{
    if(1)
    printf("hehe\n"); //if后边条件满⾜,打印⼀次hehe 
    return 0;
}
#include <stdio.h>
int main()
{
    while(1)
    printf("hehe\n"); //while后边的条件满⾜,死循环的打印hehe 
    return 0;
}

这就是他们的区别,while语句是可以实现循环效果的。

6.2 while 语句的执行流程

6.3 while 循环的实践

练习1:在屏幕上打印 1~10 的值

#include <stdio.h>
int main()
{
    int i = 1;
    while(i<=10)
    {
        printf("%d ", i);
        i = i+1;
    }
    return 0;
}

练习2:输⼊⼀个正的整数,逆序打印这个整数的每⼀位 例如:

输⼊:1234,输出:4 3 2 1

输⼊:521,输出:1 2 5

#include <stdio.h>
int main()
{
    int n = 0;
    scanf("%d", &n);
    while(n)
    {
        printf("%d ", n%10);
        n /= 10;
    }
    return 0;
}

7. for循环

7.1 语法形式

for 循环是三种循环中使⽤最多的, for 循环的语法形式如下:

for(表达式1; 表达式2; 表达式3)
 语句;//如果循环体想包含更多的语句,可以加上⼤括号 

表达式1:⽤于循环变量的初始化

表达式2:⽤于循环结束条件的判断

表达式3:⽤于循环变量的调整

7.2 for循环的执行流程

⾸先执行表达式1 初始化循环变量,接下来就是执行表达式2的判断部分, 表达式2的结果如果 ==0,则循环结束; 表达式2的结果如果!=0则执行循环语句,循环语句执行完后,再去执行表达式 3 ,调整循环变量,然后再去表达式2 的地方执行判断, 表达式2的结果是否为0,决定循环是否继 续。 整个循环的过程中,表达式1初始化部分只被执行1次,剩下的就是表达式2、循环语句、表达式3在循环。

7.3 for循环的实践

练习1:在屏幕上打印1~10的值

#include <stdio.h>
int main()
{
    int i = 0;
    for(i=1; i<=10; i++)
    {
        printf("%d ", i);
    }
    return 0;
}

练习2:计算1~100之间3的倍数的数字之和

#include <stdio.h>
int main()
{
    int i = 0;
    int sum = 0;
    for(i=3; i<=100; i+=3)
    {
        sum += i;
    }
    printf("%d\n", sum);
    return 0;
}

8. do-while循环

8.1 语法形式

在循环语句中 do while 语句的使⽤最少,它的语法如下:

do
 语句;
while(表达式);

while 和 for 这两种循环都是先判断,条件如果满足就进⼊循环,执行循环语句,如果不满足就跳 出循环; 而do while 循环则是先直接进⼊循环体,执行循环语句,然后再执行while 后的判断表达式,表达式为真,就会进行下⼀次,表达式为假,则不再继续循环

8.2 do while循环的执行流程

在 do while 循环中先执行图上的“语句”,执行完语句,在去执行“判断表达式”,判断表达式的结果是!=0,则继续循环,执行循环语句;判断表达式的结果==0,则循环结束。所以在 do while 语句中循环体是至少执行⼀次的,这是 do while 循环比较特殊的地方。

8.3 do while循环的实践

练习1:在屏幕上打印1~10的值

#include <stdio.h>
int main()
{
    int i = 1;
    do
    {
        printf("%d ", i);
        i = i + 1;
    }while(i<=10);
 
    return 0;
}

练习2:输⼊⼀个正整数,计算这个整数是⼏位数?

例如: 输⼊:1234 输出:4

            输⼊:12     输出:2

#include <stdio.h>
int main()
{
    int n = 0;
    scanf("%d", &n);
    int cnt = 0;
    do
    {
        cnt++;
        n = n / 10;
    } while (n);
    printf("%d\n", cnt);
    return 0;
}

9. break和continue语句

在循环执行的过程中,如果某些状况发生的时候,需要提前终止循环,这是非常常见的现象。C语言中提供了 break 和 continue 两个关键字,就是应用到循环中的。

break 的作用是用于永久的终止循环,只要 break 被执行,直接就会跳出循环,继续往后执行。 continue 的作用是跳过本次循环中 continue 后边的代码,在 for 循环和 while 循环中有所差异的

9.1 while循环中的break和continue

#include <stdio.h>
int main()
{
    int i = 1;
    while(i<=10)
    {
        if(i == 5)
        break;//当i等于5后,就执⾏break,循环就终⽌了 
        printf("%d ", i);//1 2 3 4
        i = i+1;
    }
    return 0;
}

打印了1,2,3,4后,当i等于5的时候,循环在 break 的地方终止,不再打印,不再循环。所以 break 的作用就是永久的终止循环,只要 break 被执行, break 外的第⼀层循环就终止了。 那以后我们在循环中,想在某种条件下终止循环,则可以使用 break 来完成我们想要的效果。

#include <stdio.h>
int main()
{
    int i = 1;
    while(i<=10)
    {
        if(i == 5)
        continue;
         //当i等于5后,就执⾏continue,直接跳过continue的代码,去循环的判断的地⽅ 
         //因为这⾥跳过了i = i+1,所以i⼀直为5,程序陷⼊和死循环 
        printf("%d ", i);    
        i = i+1;
    }
    return 0;
}

到这里我们就能分析出来, continue 可以帮助我们跳过某⼀次循环 continue 后边的代码,直接到循环的判断部分,进行下⼀次循环的判断,如果循环的调整是在 continue 后边的话,可能会造成 死循环。

9.2 for循环中的break和continue

#include <stdio.h>
int main()
{
    int i = 1;
    for(i=1; i<=10; i++)
    {
        if(i == 5)
        break;
        printf("%d ", i);//1 2 3 4
    }
    return 0;
}
#include <stdio.h>
int main()
{
    int i = 1;
    for(i=1; i<=10; i++)
    {
        if(i == 5)
        continue;//这⾥continue跳过了后边的打印,来到了i++的调整部分 
        printf("%d ", i);//1 2 3 4 6 7 8 9 10
     }
    return 0;
}

所以在 for 循环中 continue 的作⽤是跳过本次循环中 continue 后的代码,直接去到循环的调整部分。未来当某个条件发生的时候,本次循环无需再执行后续某些操作的时候,就可以使用continue 来实现。

10. 循环的嵌套

前⾯学习了三种循环 while , do while , for ,这三种循环往往会嵌套在⼀起才能更好的解决问题,就是我们所说的:循环嵌套,这里我们就看⼀个例子。

练习:

找出100~200之间的素数,并打印在屏幕上。

注:素数又称质数,只能被1和本身整除的数字。

#include <stdio.h>
#include<math.h>
int main()
{
    int i = 0;
    //循环产⽣100~200的数字 
    for(i=101; i<200; i+=2)
    {
    //判断i是否为素数 
    //循环产⽣2~i-1之间的数字 
    int j = 0;
    int flag = 1;//假设i是素数 
    for(j=2; j<sqrt(i); j++)
    {
        if(i % j == 0)
            {
                flag = 0;
                break;
            }
    }
    if(flag == 1)
    printf("%d ", i);
    }
    return 0;
}

11. goto语句

C语⾔提供了⼀种⾮常特别的语法,就是 goto 语句和跳转标号, goto 语句可以实现在同⼀个函数 内跳转到设置好的标号处。

例如:

#include <stdio.h>
int main()
{
    printf("hehe\n");
    goto next;
    printf("haha\n");
next:
    printf("跳过了haha的打印\n"); 
    return 0;
}

goto 语句如果使用的不当,就会导致在函数内部随意乱跳转,打乱程序的执行流程,所以我们的建议是能不⽤尽量不去使用;

但是 goto 语句也不是一无是处,在多层循环的代码中,如果想快速跳出,使用goto 就非常的方便了。

例如:

for(...)
{
    for(...)
    {
        for(...)
            {
                if(disaster)
                    goto error;
            }
    }
}
error:
 //...

本来 for 循环想提前退出得使用break ,⼀个 break 只能跳出⼀层 for 循环,如果3层循环嵌套 就得使⽤3个 break 才能跳出循环,所以在这种情况下我们使用goto语句就会更加的快捷。

12. 猜数字游戏

12.1 随机数生成

12.1.1 rand

C语言提供了⼀个函数叫rand,这函数是可以生成随机数的,函数原型如下所示:

int rand (void);

rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是大部分编译器上是32767。

rand函数的使用需要包含⼀个头文件是:stdlib.h

那我们就测试⼀下rand函数,这里多调用几次,产生5个随机数:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    return 0;
}

我们先运行⼀次,看看结果,再运行⼀次再看看结果,多运行几次呢?

我们可以看到虽然⼀次运行中产生的5个数字是相对随机的,但是下⼀次运行程序生成的结果和上⼀次⼀模⼀样,这就说明有点问题。 如果再深入了解⼀下,我们就不难发现,其实rand函数生成的随机数是伪随机的,伪随机数不是真正 的随机数,是通过某种算法生成的随机数。真正的随机数的是无法预测下⼀个值是多少的。而rand函数是对⼀个叫“种子”的基准值进行运算生成的随机数。 之所以前面每次运行程序产生的随机数序列是⼀样的,那是因为rand函数生成随机数的默认种子是1。如果要生成不同的随机数,就要让种子是变化的。

12.1.2 srand

C语⾔中又提供了⼀个函数叫srand,用来初始化随机数的生成器的,srand的原型如下:

void srand (unsigned int seed);

程序中在调用rand函数之前先调用srand函数,通过srand函数的参数seed来设置rand函数生成随 机数的时候的种子,只要种子在变化,每次生成的随机数序列也就变化起来了。 那也就是说给srand的种子是如果是随机的,rand就能生成随机数;在生成随机数的时候又需要⼀个随 机数,这就矛盾了。

12.1.3 time

在程序中我们⼀般是使用程序运行的时间作为种子的,因为时间时刻在发生变化的。 在C语言中有⼀个函数叫time,就可以获得这个时间,time函数原型如下:

time_t time (time_t* timer);

time函数会返回当前的日历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运行时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t类型本质上其实就是32位或者64位的整型类 型。

time函数的参数timer如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存 中带回去。

如果timer是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。

time函数的时候需要包含头⽂件:time.h

如果只是让time函数返回时间戳,我们就可以这样写:

time(NULL);//调⽤time函数返回时间戳,这⾥没有接收返回值 

那我们就可以让⽣成随机数的代码改写成如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
    //使⽤time函数的返回值设置种⼦ 
    //因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换 
    srand((unsigned int)time(NULL));
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    return 0;
}

srand函数是不需要频繁调用的,⼀次运行的程序中调用⼀次就够了。

12.1.4 设置随机数的范围

如果我们要生成0~99之间的随机数,方法如下:

rand() % 100;//余数的范围是0~99 

所以如果要生成a~b的随机数,方法如下:

a + rand()%(b-a+1)

12.2 猜数字游戏的实现

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


void menu()
{
    printf("***********************\n");
    printf("****** 1. play ********\n");
    printf("****** 0. exit ********\n");
    printf("***********************\n");
}


void game()
{
    int r = rand()%100+1;
    int guess= 0;
    while(1)
    {
        printf("请猜数字>:");
        scanf("%d", &guess);
        if(guess < r)
        {
            printf("猜⼩了\n");
        }
        else if(guess > r)
        {
            printf("猜⼤了\n");
        }
        else
        {
            printf("恭喜你,猜对了\n");
            break;
        }
    } 
}


int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch(input)
        {
            case 1:
                game();
                break;
            case 0:
                printf("游戏结束\n");
                break;
            default:
                printf("选择错误,重新选择\n");
                break;
        }
    }while(input);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值