目录

循环语句

一、while循环

二、for循环

三、do...while循环

四、循环语句练习

getchar 与 putchar

总结


循环语句

 if 语句:当条件满足的情况下,if语句后的语句执行,否则不执行。但是这个语句只会执行一次。

生活中很多的实际的例子是:同一件事情我们需要完成很多次。
C语言中给我们引入了循环语句。

C语言中有三种循环语句:

  • while循环
  • for循环
  • do...while循环

一、while循环

1、语法结构

while(表达式)
 {
        循环语句;
 }

2、while循环的执行流程

 3、while循环的使用

打印1~100之间的整数

#include<stdio.h>
int main()
{//打印1~100int i = 1;while (i <= 100){printf("%d ", i);//每打印10个数换行if (i % 10 == 0){printf("\n");}i++;}return 0;
}

运行结果:

4、while循环中的break和continue

(1)break

break在循环中的作用:

在循环中只要遇到break,就终止循环(跳出循环)。

while循环遇到break

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

运行结果:

代码分析:

当 i 等于5时程序执行break语句,while循环中遇到break,就会跳出循环不会再执行break后的语句。所以最后只打印了 1 2 3 4

(2)continue

continue在循环中的作用就是:

continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到循环语句的判断部分。进行下一次循环的入口判断。

while循环遇到continue


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

运行结果:

代码分析:

当 i 等于5时程序执行continue语句,while中遇到continue,本次循环中continue后边的代码不会再执行,直接跳转到while语句的判断部分。但是i++;这条语句在continue后面,所以 i 的值不会再发生变化,i 的值一直都是5。所以程序进入了死循环,最终打印 1 2 3 4....(4的循环)一直循环。


二、for循环

1、语法结构

for(表达式1;表达式2;表达式3)

循环语句;

每个表达式的作用:

  • 表达式1:表达式1为初始化部分,用于初始化循环变量的。
  • 表达式2:表达式2为条件判断部分,用于判断循环时候终止。
  • 表达式3:表达式3为调整部分,用于循环条件的调整。

 2、for循环的执行流程

 3、for循环的使用

打印1~10之间的整数

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

运行结果:

4、for循环中的break和continue

(1)break

#include<stdio.h>
int main()
{int i = 0;for (i = 1; i <= 10; i++){if (5 == i){break;}printf("%d ", i);}//打印完以后换行printf("\n");return 0;
}

运行结果:

代码分析:

当 i 等于5时程序执行break语句,for循环中遇到break,就会跳出循环不会再执行break后的语句。所以最后只打印了 1 2 3 4

(2)continue

#include<stdio.h>
int main()
{int i = 0;for (i = 1; i <= 10; i++){if (5 == i){continue;}printf("%d ", i);}//打印完以后换行printf("\n");return 0;
}

运行结果:

代码分析:

当 i 等于5时程序执行continue语句,for循环中遇到continue,本次循环中continue后边的语句不会再执行,直接跳转到for循环中的表达式3(i++)再执行表达式2进行判断(满足条件进入循环)。执行表达式3以后 i 的值变成了6(6不等于5)循环中 if 的条件不成立,程序往下执行输出6,再执行表达式3(i++)再执行表达式2直到表达式2的条件不成立,程序跳出循环。最后输出 1 2 3 4 6 7 8 9 10。

5、for语句的循环控制变量

建议:

  1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。
  2. 建议for语句的循环控制变量的取值采用“前闭后开区间”写法。

(1)如果在for循环内修改循环变量,会造成死循环

#include<stdio.h>
int main()
{int i = 0; //不好的习惯for (i = 1; i <= 10; i++){i = 0;printf("hello\n");}return 0;
}

运行结果

(2)for语句的循环控制变量的取值采用“前闭后开区间”

#include<stdio.h>
int main()
{int i = 0;//代码1printf("代码1:\n");for (i = 0; i < 10; i++){printf("hello\n");}printf("-------------------\n");//代码2printf("代码2:\n");for (i = 0; i <= 9; i++){printf("hello\n");}return 0;
}

运行结果:

代码1采用了“前闭后开区间”写法,代码2前后都是闭区间,代码1与代码2的执行结果相同,但是代码1的可读性更好一些。

这里只是建议写成将循环的控制变量的取值写成“前闭后开区间”,根据个人习惯使用。

6、for循环的变种

#include<stdio.h>
int main()
{for (;;){printf("hello\n");}return 0;
}
  1. for循环的初始化(表达式1)、判断(表达式2)、调整(表达式3)三个部分可以省略。
  2. 判断部分(表达式2)如果省略,意味着判断恒为真,就构成了死循环

   如果条件允许,不建议省略for循环的3个表达式。

如果省略了for循环的表达式,得到的可能不是预期的结果

#include<stdio.h>
int main()
{int i = 0;int j = 0;for (i=0;i<3;i++){for (j = 0; j < 3; j++){printf("hello\n");}}return 0;
}

运行结果:

代码分析:

for循环是可以嵌套的。i = 0时执行里面的for循环输出3个hello;i = 1时执行里面的for循环输出3个hello;i = 2时执行里面的for循环输出3个hello,然后跳出循环。3*3=9,最后打印了9个hello。

如果省略两个for循环中的表达式1,结果会是怎样的呢?

#include<stdio.h>
int main()
{int i = 0;int j = 0;for (;i<3;i++){for (; j < 3; j++){printf("hello\n");}}return 0;
}

运行结果:

代码分析:

  • i = 0 时进入循环执行里面的for循环(j=0 输出一个hello,再执行j++,再判断,直到 j 为3时跳出循环)输出3个hello。
  • 当i = 1时进入循环,此时里面的for循环 j 没有初始化(此时值为3),j 值为3跳出里面的循环。程序再执行i++。当 i = 2时进入循环,此时里面的for循环 j 没有初始化(此时值为3),j 值为3跳出里面的循环。最后程序只输出了3个hello。

for循环中,表达式1、表达式2、表达式3,可以同时写多个变量。

#include<stdio.h>
int main()
{int i = 0, j = 0;for (i = 0, j = 0; i < 3 && j < 5; ++i, j++){printf("hello\n");}return 0;
}

了解了for循环以后,可以发现for循环与while循环中都存在三个必须条件(三个表达式)。但由于语法结构,使得while循环中的三个表达式太过于分离,这样在修改代码的时候就不太方便,而for循环中的三个表达式是放在一起的。所以for循环的语法结构更好一些,使用频率也是最高的。

做一道题,看看是否真的理解了for循环

下面这段代码循环了几次?

#include<stdio.h>
int main()
{int i = 0;int k = 0;for (i = 0, k = 0; k = 0; i++, k++){k++;printf("hello\n");}return 0;
}

因为表达式2(判断条件)是k赋值为0,所以循环的条件为假不会进入到循环里,所以循环次数为0。


三、do...while循环

1、语法结构

do

循环语句;

while(表达式);

2、do...while循环的执行流程

3、do...while循环的使用

打印1~10之间的整数

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

运行结果:

4、do...while循环中的break和continue

(1)break

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

运行结果:

代码分析:

当 i 等于5时程序执行break语句,do...while循环中遇到break,就会跳出循环不会再执行break后的语句。所以最后只打印了 1 2 3 4

 (2)continue

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

运行结果:

代码分析:

当 i 等于5时程序执行continue语句,do...while中遇到continue,本次循环中continue后边的代码不会再执行,直接跳转到do...while语句的判断部分。但是i++;这条语句在continue后面,所以i 的值不会再发生变化,i 的值一直都是5。所以程序进入了死循环,最终打印 1 2 3 4.....(4的循环)一直循环。

5、do...while循环的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。


四、循环语句练习

1、计算n的阶乘

  1. 输入 n
  2. 产生1~n的数字,累积乘在一起
  3. 打印出来
#include<stdio.h>
int main()
{int n = 0;int i = 0;int ret = 1;scanf("%d", &n);for (i = 1; i <= n; i++){ret *= i;}printf("%d\n", ret);return 0;
}

这里的n不要输入的太大,int类型存储的数据是有限的。

2、计算1~10的阶乘和

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

这种算法程序执行效率太低

代码优化:

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

3、在一个有序数组中查找具体的某个数字n。

方法一(顺序查找):

#include<stdio.h>
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 7;int i = 0;for (i = 0; i < 10; i++){if (arr[i] == k){printf("找到了,下标是%d\n", i);break;}}if (10 == i){printf("找不到\n");}return 0;
}

这种方法是将k的值与数组中的元素一个一个的进行比较。这种方法虽然能解决这个问题,但是效率太低。

方法二(二分查找):

简单说一下二分查找:

  • 在一个有序的数组中,先查找中间元素。数组中有10个数,数组下标为:0~9。
  • 如果待查找的元素比中间元素小,就将查找的范围缩小一半在中间元素的左边查找(此时查找的数组左下标为0,右下标为中间元素的下标-1)。
  • 如果待查找的元素比中间元素大,就将查找的范围缩小一半在中间元素的右边查找(此时查找的数组左下标为中间元素的下标+1,右下标为9)。

这只是进行了一次二分查找,如果要在数组中找到待查找的数,就要进行多次二分查找。

循环的结束条件为 左下标>右下标(因为当左下标>右下标时表示整个数组已经查找完)。

  • 如果找到了就输出:找到了,并输出该元素的下标。
  • 如果没找到就输出:没找到。

放一张图帮助理解

代码:


#include<stdio.h>
int main()
{int arr[] = { 10,20,30,40,50,60,70,80,90,100 };int k = 70;int sz = sizeof(arr) / sizeof(arr[0]);int left = 0;int right = sz - 1;int mid = 0;while (left <= right){mid = (left + right) / 2;if (k > arr[mid]){left = mid + 1;}else if (k < arr[mid]){right = mid - 1;}else{printf("找到了,下标为%d\n", mid);break;}}if (left > right){printf("找不到\n");}return 0;
}

int sz = sizeof(arr) / sizeof(arr[0]);  计算数组元素个数

  • sizeof(数组名)计算的是数组的总大小,单位是字节。
  • arr数组中总共有10个元素,每个元素都是整型占4个字节空间,sizeof(arr)计算出来就是40。
  • sizeof(arr[0])计算的是第一元素的大小(4)。
  • sz = sizeof(arr) / sizeof(arr[0])  = 40 / 4 = 10

4、编写代码,演示多个字符从两端移动,向中间汇聚。

要实现的过程:两个字符串

arr1: Hello World!

arr2: ############

  1. H##########!
  2. He########d!
  3. Hel######ld!
  4. ……
  5. Hello World!

代码:

#include<stdio.h>
#include<String.h>
int main()
{char arr1[] = "Hello World!";char arr2[] = "############";int left = 0;int right = strlen(arr1) - 1; //strlen - 求字符串长度while (left <= right){arr2[left] = arr1[left];arr2[right] = arr1[right];printf("%s\n", arr2);left++;right--;}return 0;
}

可以将程序运行的结果以动态的形式展示

#include<stdio.h>
#include<String.h>
#include<windows.h>
int main()
{char arr1[] = "Hello World!";char arr2[] = "############";int left = 0;int right = strlen(arr1) - 1; //strlen - 求字符串长度while (left <= right){arr2[left] = arr1[left];arr2[right] = arr1[right];printf("%s\n", arr2);//windows 提供的函数Sleep(1000);//睡眠函数 - 单位是毫秒system("cls");//执行系统命令 - cls:清空屏幕left++;right--;}printf("%s\n", arr2);return 0;
}

感兴趣的朋友可以运行一下看看代码执行的结果


getchar 与 putchar

输入可以使用scanf 函数,如果想要输入字符也可以使用getchar函数(getchar函数只能用来输入字符)。

getchar - 获取(输入)一个字符

从键盘中获取一个字符,通过返回的方式带回一个值(这个值就是获取的字符),返回值类型为 int 。

getchar 函数的使用

#include<stdio.h>
int main()
{int ch = 0;//scanf("%d",&ch);//输入a的ASCII码值(97)ch = getchar();printf("%c\n", ch);//%c - 打印字符return 0;
}

运行结果:

getchar是获取一个字符,为什么要使用 int 类型的变量来接收这个字符呢?

两个原因:

  1. getchar返回的是一个字符,而字符在内存中的存储是以ASCII码值的形式存储的,比如小写a在内存中存放的是97(a的ASCII码值为97),97是一个整数,所以将 getchar 函数的返回值放到一个整型变量中是没有任何问题的。
  2. getchar函数读取失败的时候返回EOF(-1),而 -1 是一个整数占4个字节的空间,char 类型是存放字符的(一个字符只有1个字节的空间)。如果将 -1 放到char类型变量中是放不下的,所以综合考虑将 getchar函数 的返回值放到 int 类型的变量中。

#include<stdio.h>
int main()
{int ch = 0;while ((ch = getchar()) != EOF)putchar(ch);return 0;
}

运行结果:

代码分析:

getchar一次只能读取一个字符,但是在while循环中可以读取多个字符。

putchar一次只能输出一个字符,但是在while循环中可以打印多个字符。

  • -1指的是getchar读取字符失败返回的值,但是当你输入 -1的时候,getchar读取-1并没有失败,所以输入-1循环不会终止。
  • 如果输入EOF,getchar每次只能获取一个字符,虽然输入了三个字符,但每次的返回值都是一个字符的ASCII码值,会返回3次。这3次中的getchar读取字符都没有失败,所以不会返回-1,所以循环不会终止。
  • 当输入Ctrl+z时,getchar读取失败然后返回-1,所以才会终止循环。

输出可以使用 printf 函数,如果想要输出字符也可以使用putchar函数(putchar函数只能用来输出字符)。

putcahr - 输出一个字符:将获取到的字符输出到屏幕上。

 putchar 函数的使用

#include<stdio.h>
int main()
{int ch = 0;//scanf("%d",&ch);//输入a的ASCII码值(97)ch = getchar();//printf("%c\n", ch);//%c - 打印字符putchar(ch);return 0;
}

运行结果

#include<stdio.h>
int main()
{char input[20] = { 0 };printf("请输入密码:>");scanf("%s", input);printf("请确认密码(Y/N):>");int ch = getchar();if ('Y' == ch){printf("确认成功\n");}else{printf("确认失败\n");}return 0;
}

运行结果:

程序的本意是:输入密码,再输入Y 或 N 确认密码,输入Y屏幕输出确认成功,输入N屏幕输出确认失。可是当输完密码后按回车键,程序直接输出确认失败。

程序执行的结果偏离了我们的本意,为什么会这样呢?

原因:

  • 程序运行以后,在屏幕上输出:请输入密码:> 这个时候程序在等待着我们去输入密码。而scanf 读取的数据是从键盘中输入的数据。
  • scanf 在读取数据的时候并不是直接从键盘中获取数据,从键盘输入数据的时候有一个输入缓冲区。当scanf 在工作的时候会到输入缓冲区中获取数据(如果输入缓冲区中有数据,scanf就会直接拿走缓冲区的数据;如果输入缓冲区中没有数据,scanf 就会一直等待键盘输入数据,然后再读取数据)。
  • 程序中输入密码:abcdef,为了让scanf获取到密码(abcdef)还要在键盘上敲回车键(相当于\n),敲回车是为了让input获取密码(abcdef)。此时输入缓冲区中存放的数据为:abcdef\n,当敲完回车键后 abcdef 就被scanf拿走。
  • abcdef被拿走后输入缓冲区还剩下一个字符 '\n',此时程序会输出:请确认密码(Y/N):> 。然后getchar开始工作,getchar也是从输入缓冲区中获取数据(如果缓冲区中有数据getchar就会直接拿走数据,如果缓冲区没有数据getchar就会等待键盘输入数据,然后再读取数据)。
  • 此时缓冲区里还有一个字符'\n',getchar就会直接拿走'\n' 将'\n'放到变量ch里。此时ch再进行判断:ch不等于Y,程序就走到else语句中,然后输出"确认失败"。
  • 得出:getchar在拿取缓冲区的数据时,因为缓冲区里有数据('\n')所以程序不会等待着让我们输入 (Y 或 N ),如果缓冲区中没有数据,那么getchar就会等待键盘输入信息放到缓冲区里,然后再从缓冲区中读取数据,再进行判断。

解决办法:在scanf后面再写一个getchar,让第一个getchar先将缓冲区中的'\n'拿走(此时的getchar不需要返回值),再执行第二个getchar的时候缓冲区里就没有数据了,这个时候程序就会等待我们输入数据。

修改后的代码:

#include<stdio.h>
int main()
{char input[20] = { 0 };printf("请输入密码:>");scanf("%s", input);getchar();//拿走'\n'printf("请确认密码(Y/N):>");int ch = getchar();if ('Y' == ch){printf("确认成功\n");}else{printf("确认失败\n");}return 0;
}

运行结果:

但是此时程序还是有问题,如果有人在输入密码的时候中间加了空格,程序执行的结果依旧不是我们想要的结果:

补充:scanf("%s",....); 读取字符串的时候,遇到空格或换行('\n')就结束了。如果在字符串中想要读取空格可以使用gets函数。这里只是提一下gets函数,后期会详细说这个函数。

代码分析:

  • scanf在输入缓冲区中读取数据时,当读取到abcdef后面的空格时就不会再读取了,此时缓冲区中还剩下:空格abc\n。
  • 程序往下执行到第一个getchar时只能拿走缓冲区里的空格字符,拿走以后缓冲区中还有:abc\n。
  • 程序再往下执行到第二个getchar时发现缓冲区中有数据就直接将a拿走,a不等于 Y 。所以程序输出:确认失败。

解决办法:

使第一个 getchar 将缓冲区里的所有数据都拿走(最后一个数据是'\n')。此时就要使用循环来读取字符,直到将'\n'也拿去。

修改后的代码:


#include<stdio.h>
int main()
{char input[20] = { 0 };printf("请输入密码:>");scanf("%s", input);int tmp = 0;//清理缓冲区while ((tmp = getchar()) != '\n'); //只循环//也可以写成//while ((tmp = getchar()) != '\n')//{// ;//空语句//}printf("请确认密码(Y/N):>");int ch = getchar();if ('Y' == ch){printf("确认成功\n");}else{printf("确认失败\n");}return 0;
}

运行结果:

scanf 函数的功能比getchar函数的功能更全, printf 函数的功能比putchar函数的功能更全。

getchar 和 putchar 只能操作字符(一次只能操作一个字符)。


总结

详细介绍了C语言中的循环语句,可能有些地方写的不是很清晰(请谅解)。

还介绍了getchar函数与putchar函数。getchar与putchar是使用文字描述的,可能会太抽象,不容易理解。

学习是循序渐进的过程,每天学一点就会有收获!

C语言初级篇-----循环语句详解相关推荐

  1. c语言输入循环语句,C语言中输入输出和循环语句详解.ppt

    C语言中输入输出和循环语句详解 C语言的输入输和循环分支语句详解 本章主要向大家介绍下C语言的输入和输出功能以及循环分支语句的使用 第4章 顺序结构程序设计 3.1 C语言语句 3.2 赋值语句 3. ...

  2. smarty手册-smarty中foreach循环语句详解

    原文地址:smarty手册-smarty中foreach循环语句详解作者:谭博 {foreach}循环也有自身属性的变量,可以通过{$smarty.foreach.name.property}访问,其 ...

  3. C语言入门篇 | 循环语句和用法(详解版)

    C语言循环语句用法有三种主要形式: for()循环 while()循环 do {} while();循环 for()循环用法: for( e1 ; e2 ; e3 ) //注意三个区域间用分号来分隔, ...

  4. C语言详解系列——循环语句详解(1)while语句的语法结构

    文章目录 while语句 break continue while语句 之前的学习中我们了解到了if语句的用法,这个语句只会执行一次,但在我们的生活当中有许多事情是需要重复去做的,那我们应该怎么实现呢 ...

  5. C语言详解系列——循环语句详解(3)do while语句的语法结构

    文章目录 do while语句 do while语句中的break和continue break continue do while语句与while语句的不同点 简单练习 do while语句 之前的 ...

  6. C语言详解系列——循环语句详解(2)for语句的语法结构

    文章目录 for语句 break与continue 关于if语句的建议 关于for循环的变种写法 一道笔试题 for语句 在之前的学习中我们已经了解到了循环结构中while语句的用法,那么为什么我们还 ...

  7. python循环语句-详解Python中的循环语句的用法

    一.简介 Python的条件和循环语句,决定了程序的控制流程,体现结构的多样性.须重要理解,if.while.for以及与它们相搭配的 else. elif.break.continue和pass语句 ...

  8. matlab循环语句详解

    MATLAB中的循环语句是一种方便的编程结构,可以帮助处理迭代过程中的数据和控制流.MATLAB提供了三种基本类型的循环语句:for循环.while循环和do-while循环.这篇文章将介绍这些循环语 ...

  9. PHP循环语句详解 while, for, foreach, do while

    一.while循环  while(表达式) { 循环体;//反复执行,直到表达式为假 } 代码: $index = 1; while ($index<5) { print "Numbe ...

最新文章

  1. JDBC Driver常用连接方法列表
  2. 如何用java+tomcat来创建网站服务器
  3. 如何使用 Istio 进行多集群部署管理:多控制平面
  4. 维护没有源代码的遗留 Java 项目
  5. CSV格式数据如何导入MySQL?
  6. C及opencv指针释放问题
  7. C++中引用与指针的区别(详细介绍)
  8. mysql 非自然月统计_MySQL性能优化 — 实践篇1
  9. 关于npm邮箱验证问题
  10. git pull 出错,error: Your local changes to the following files would be overwritten by merge...
  11. 2.4 sklearn中的metrics.roc_auc_score评价指标
  12. Centos7安装32位库用来安装32位软件程序
  13. 为什么局域网需要https加密?如何选择内网SSL证书?
  14. java画乌龟_简单的实现java多线程——龟兔赛跑
  15. 【jzoj1592】【二分】【GDKOI训练】音乐节拍
  16. mysql拼图游戏代码_HTML+Javascript制作拼图小游戏详解(二)
  17. 含有中文的图片正常显示(微信小程序)
  18. Batch Normalization在CNN中的原理,nb与lrb的区别
  19. IOS - 怎么辨别苹果手机的数据线是否原装?
  20. 写论文比较有用的网站

热门文章

  1. G1D19-DPCS KEAttacKG复现
  2. ceph-mimic版本的安装使用1
  3. Spring 源码中设计模式?这样回答面试官.才能显得你技高一筹.
  4. cocoscreator 动态创建帧动画
  5. 电脑高手常用的五个按钮
  6. springboot处理参数再转发请求_Springboot 2.0---WebFlux请求处理流程
  7. 移动端UI框架小汇总
  8. STM32的USART_GetFlagStatus和USART_GetITStatus解析
  9. Echarts --- 可视化练习(pie01 --- 南丁格尔玫瑰图)
  10. 远程桌面连接时,用电脑名不能连接,用IP就可以,为什么