9. C 语言 -- 循环结构:while语句和 do … while语句

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dugudaibo/article/details/82866006

本博客主要内容为 “小甲鱼” 视频课程《带你学C带你飞》【第一季】 学习笔记,文章的主题内容均来自该课程,在这里仅作学习交流。在文章中可能出现一些错误或者不准确的地方,如发现请积极指出,十分感谢。
也欢迎大家一起讨论交流,如果你觉得这篇文章对你有所帮助,记得评论、点赞哦 ~(。・∀・)ノ゙

1. 循环结构

  循环结构是编程中常常使用的结构,当在程序中存在着需要循环执行多次的代码时,可以采用循环结构实现。在 C 语言中常见的是 while 循环和 for 循环,在这里首先介绍 while 循环。

2. while 循环结构

2.1 while 语句

  while 语句的语法非常简单,使用方法如下

while (表达式)
    循环体

只要表达式的值为真,就会不断执行循环体里边的语句或程序块,如下图所示

举例说明

示例1

  现在我们要计算1+2+3+……+100的结果,可以画出如下的流程图

根据流程图可以得到如下的程序

#include<stdio.h>

int main()
{
        int i = 1, sum = 0;
        while (i <= 100)
        {
                sum = sum + i;
                i = i+1;
        }
        printf("result is %d\n",sum);
        return 0;
}

示例2

  统计从键盘输入的一行英文句子的字符个数,其流程图如下所示

根据流程图可以得到如下代码

#include<stdio.h>

int main()
{
        int count = 0;
        printf("please input a english setence:");
        while (getchar() != '\n')
        {
                count = count +1;
        }
        printf("it has %d words \n",count);
        return 0;
}

  在ubuntu16.04下通过gcc编译执行得到如下结果
在这里插入图片描述
其中 34 个字符包含了其中的空格。

2.2 do … while 语句

  while 语句的语法非常简单,使用方法如下

do
    循环体
while (表达式);

这里需要注意的是,在 while (表达式); 的后面有一个分号,但是在上一个的中 while (表达式) 是没有分号的。do…whilewhile 语句相反,先执行循环体的内容再判断表达式是否为真,如下图所示

  这种循环结构比较特殊,常常用于用户登陆密码验证问题,当输入的密码不正确的时候会要求一直输入密码直至正确(当然生活中的密码往往只可以进行有限次的尝试),常常采用如下左图的使用方式
在这里插入图片描述
因为如果采用 while 语句而不是采用 do … while 语句,就会产生上图中右图的现场,代码会有两部分十分相近。

2.3 小结

  对于上述的两种循环,其中的 while 语句是入口循环条件, do … while 语句是出口循环条件,其中入口循环条件是首先判断条件是否满足,然后在执行循环体内容;而出口循环条件是先执行循环体,然后判断条件是否满足,因此循环体的内容至少会执行一次。

3. C 语言的三种输入函数

  在这里介绍 C 语言中的三种输入函数,scanf()getchar()gets() 都是标准输入函数,比如在本文中使用的 getchar() ,但是在使用有一些不同。 [ 2 ] ^{[2]}

3.1 输入操作的原理

  在介绍输入函数之前,首先介绍输入操作的原理, 程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入。所以我们在使用不同的输入函数时,要考虑在输入缓冲区是否会造成残留的现象。

3.2 三种输入函数用法

  gets()用于从标准输入流stdin读入一个整行(以’\n’或EOF)结束,写入ptr指向的字符数组,并返回这个指针;出错或遇到文件结束时则返回NULL。行末的’\n’从流中取出,但不写入数组。gets()不检查被写入的数组大小。

  getchar()用于从标准输入流stdin读入一个字符,并返回这个字符。如果读到文件结尾,则返回EOF。注意到EOF不能用char类型表示,所以getchar()函数返回的是一个int型的数。使用时也应该注意这一点。

  scanf()函数返回成功赋值的数据项数,出错时则返回EOF,与上面相同,scanf()函数返回的也是一个int型的数。

  因此getchar()常用于接收字符,而gets()常用于接受字符串,scanf()可用于接受字符也可以用于接收字符串。

3.3 三种输入函数的注意事项

  首先要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题。

  读取字符时
  (1) scanf()以 Enter 结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
  (2) getchar()以 Enter 结束输入,不会舍弃最后的回车符。

  读取字符串时
  (1) scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符;
  (2) gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!

所以当我们项读取一句话中的每一个字符的时候,往往使用 getchar() 而不使用 scanf(),因为一句话中是会出现空格的,如果使用 scanf() 会造成将一句话分首先读入第一个空格前的部分,其余部分会残留在输入缓冲区的情况,所以不适合。

  其次为了避免出现上述问题,必须要在读取输入前,清空缓冲区的残留数据,可以用以下的方法解决:
  (1) C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了,即使用fflush(stdin)。某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(linux 下的 gcc 就不支持),因为标准中根本没有定义 fflush(stdin),所以这种方法的移植性不是很好不建议使用;
  (2) 自己取出缓冲区里的残留数据,即使用 while ((c = getchar()) != EOF && c != '\n');,不停地使用getchar()获取缓冲中字符,直到获取的c是“\n”或文件结尾符EOF为止。

3.4 举例说明

  使用 scanf()getchar()输入读入字符的示例如下所示

#include <stdio.h>

int main()
{
        char char1, char2, char3, char4;
        scanf("%c%c%c%c", &char1, &char2, &char3, &char4);
        printf("%d %d %d %d\n", char1, char2, char3, char4);

        char c;
        int i;

        scanf("%c%d", &c, &i);
        printf("变量c的值是:%c\n", c);
        printf("变量i的值是:%d\n", i);

        // fflush(stdin);
        while ((c = getchar()) != EOF && c != '\n');

        char ch1, ch2, ch3, ch4;
        ch1 = getchar();
        ch2 = getchar();
        ch3 = getchar();
        ch4 = getchar();
        printf("%d %d %d %d\n", ch1, ch2, ch3, ch4);
        return 0;
}

执行上面的代码可以获得如下的结果
在这里插入图片描述
这里可以看到,对于输入 “a b”, scanf()将空格与回车符均作为输入,并且打印输出他们的 ascii 码;之后的 scanf() 没有打印输出空格的 ascii 码,是因为定义的输入是 int 型,所以没有将空格这个字符读入;getchar()获得的结果与 scanf()是一样的。

  其次可以看到我们在这里清楚了输入缓冲区中的残留,否则 getchar()会先读取缓冲区残留的回车,然后在读入键盘输入的部分;fflush(stdin)在 ubuntu 下不可用,所以注释掉了。

  使用 scanf()fgets()输入读入字符的示例如下所示

#include <stdio.h>

int main()
{
        char str1[20], str2[20];
        printf("input is:");
        scanf("%s",str1); 
        printf("output is : %s\n",str1);    
        scanf("%s",str2); 
        printf("output is : %s\n",str2); 

        char c;
        while ((c = getchar()) != EOF && c != '\n');
        
        printf("input is:");
        char str3[20], str4[20];
        fgets(str3, 20, stdin); 
        printf("output is : %s\n",str3);    
        fgets(str4, 20, stdin); 
        printf("output is : %s\n",str4); 
        return 0;
}

这里有两点需要注意,首先 gets() 在 ubuntu 下事会报错的,所以在这里使用 fgets() 替代,其次由于 scanf 不会清除最后的回车符号,所以这里我们还是手动清除缓冲区残留,执行后的结果如下所示
在这里插入图片描述
所以建议使用fgets()读入字符串。

参考

[1] “小甲鱼” 视频课程《带你学C带你飞》【第一季】P13
[2] hao5743《scanf()和getchar() 使用》
[3] dophiJing CSDN 博客 《gets与scanf如何判断读取文件结束》
[4] guanyasu CSDN 博客《C语言清空输入缓冲区》

欢迎大家关注我的知乎号(左侧)和经常投稿的微信公众号(右侧)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/dugudaibo/article/details/82866006