零基础玩转C语言系列第三章——循环语句

阅读 116

2022-05-10


【前言】:循环语句补充的知识点都挺重要的哦,铁汁们要用点心记哦。

一、while语句

while语句

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


【敲黑板】:条件表达式的执行次数比循环体的执行次数多 1次。


循环中的break语句和continue语句:


break语句在循环中的作用:break是永久终止循环;

continue语句在循环中的作用:continue是用于终止本次循环的,也就是说本次循环中continue后面的代码不会执行,而是直接跳转到while语句的判断部分 


补充1:getchar()

函数原型:

int getchar(void)

 功能:


在标准输入缓冲区中读取一个字符,返回读到的字符的ASCII码值,如果读取失败,则返回EOF(-1)


问:为什么getchar()返回的是字符的ASCII码值?函数返回值为什么要放到一个int类型的变量中呢?不是应该放在一个char类型的变量中吗?

如:

int ch = 0;
ch = getchar();

答:


  • getchar()返回了字符的ASCII码值,ASCII码值是整数,存放在整型变量中没有任何问题;
  • 这一点也是最重要的一点,getchar()读取失败的时候返回EOF,EOF本质是-1(#define EOF -1),是一个整型值,在一个char类型中,是存储不下的;
  • 再结合getchat()函数的原型,getchar()的返回类型被定义为int, 那么返回数据应该被存放在int变量中



getchar(): 获取/输入一个字符;

putchar(): 输出一个字符

注意哦,这两个函数一次只能操作一个字符,没有scanf(),printf()功能齐全 


补充2:输入缓冲区

引入:

#include<stdio.h>

int main()
{
char input[20] = { 0 };
printf("请输入密码:>");
scanf("%s", input);//输入abcdef最后加上一个\n
printf("请确认密码:(Y / N):>");
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

此时输入缓冲区中放的是abcdef\n,scanf()函数将abcdef读走了,留下了一个\n,所以\n直接被getchar()读取,所以此时ch里面放的是\n,后面不会等到我们确认密码就直接输出确认失败了。 

零基础玩转C语言系列第三章——循环语句_i++

零基础玩转C语言系列第三章——循环语句_for循环_02

存在的问题:本题输入abcdef,然后按回车键,还没有等到我们输入字符(Y/ N)就直接输出“确认失败”了,那怎么改才能成为我们想要的呢?


在scanf()下面加上一条语句:getchar();目的只有一个,拿走回车键('\n'),


 零基础玩转C语言系列第三章——循环语句_#include_03

存在的问题:这样改只能保证输入“abcdef”时可以正常执行,但如果输入的是"abcdef hehe"时又会直接输出“确认失败”了,不信你看... 

零基础玩转C语言系列第三章——循环语句_c++_04

我丢,这什么鬼,怎么又错了!?

注意:


scanf("%s", ...); //scanf()读取字符串的时候遇到空格时就停下来不再读取了 


分析上段代码:

#include<stdio.h>

int main()
{
char input[20] = { 0 };
printf("请输入密码:>");
scanf("%s", input);//scanf()只读取了"abcdef"
getchar();//getchar()读取了一个空格,所以这里就有问题了,这里的getchar()只能拿走一个字符,我们想要的是它能将缓冲区
//里剩下字符全部拿走,直至拿走'\n'
printf("请确认密码:(Y / N):>");
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

是呀,这里的getchar()只能拿走一个字符,我们想要的是它能将缓冲区里剩下的全部拿走,直至拿走'\n',该怎么改?

#include<stdio.h>

int main()
{
char input[20] = { 0 };
printf("请输入密码:>");
scanf("%s", input);//scanf()只读取了"abcdef"

//清理缓冲区
int tmp = 0;
while ((tmp = getchar()) != '\n')
{
;//空语句,什么事都不干,拿字符就行了
}
printf("请确认密码:(Y / N):>");
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}

零基础玩转C语言系列第三章——循环语句_i++_05

这样就可以了,注意实现上面清理缓冲区的功能哦。

 二、for循环

注意:


for循环的风格更胜一筹,使用的频率也最高。


建议:


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


如:

for(i = 10; i < 10; i++)   //前闭后开

for(i = 10; i <= 10; i++) //前闭后闭(不建议这样写法,但是为了更好地解读也可以用)

一些for循环的变种:

  • for的初始化、判断、调整三个部分都可以省略;
  • 中间的判断部分如果省略就意味着判断恒为真,构成了死循环。

所以,如果条件允许,不建议省略哦。

笔试题:

//问:打印了多少次hehe?
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (; i < 3; i++)
{
for (; j < 3; j++)
{
printf("hehe\n");
}
}
return 0;
}

嘿嘿,想必铁汁心里已经有了自己的答案,看看是不是和正确答案一样呢?

零基础玩转C语言系列第三章——循环语句_c语言_06

 哈哈,说实话,我第一次做这道题目想的是9次,那为什么是3次呢?

零基础玩转C语言系列第三章——循环语句_c语言_07

 看到了吧,所以尽量不要省略for循环里面的表达式。

 再加一道笔试题:

int i = 0;
int k = 0;
for(i = 0, k = 0; k = 0; i++, k++) //k = 0为赋值,0为假,判断表达式恒为假,所以循环执行了0次
{
k++;
}

三、do...while()循环

do...while循环与前面两个循环不同的是,它的循环体至少执行一次!

do
循环语句;
while(表达式);

注意:do...while语句使用的场景有限,所以不会经常使用。

四、练习题

练习1:计算n的阶乘

伪代码:

int ret = 1;
int i = 0;
for(i = 1; i <= n; i++)
{
ret = ret * i;
}

练习2:计算1!+2!+3!+...+n!

在练习1中我们知道了计算n的阶乘的方法,所以计算1!+2!+3!+...+n!就简单多了。

来,先看一个错误示范:

//为了方便测试我在这里就简单计算到1!+2!+3!
#include<stdio.h>

int main()
{
int i = 0;
int ret = 1;
int sum = 0;
int n = 0;
for (n = 1; n <= 3; n++)
{
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
sum = sum + ret;
}

printf("%d\n", sum);
return 0;
}

实际上1!+2!+3! = 9, 但是实际上结果是...

零基础玩转C语言系列第三章——循环语句_for循环_08

结果却是15,这是为什么呢? 


因为第二层循环里面的ret是上次留下的值,而我们希望执行完一次计算某数的阶乘后,需要将ret重置为1,然后再计算下一个数的阶乘。


所以,改写代码如下:

//为了方便测试我在这里就简单计算到1!+2!+3!
#include<stdio.h>

int main()
{
int i = 0;
int ret = 1;
int sum = 0;
int n = 0;
for (n = 1; n <= 3; n++)
{
ret = 1;//注意哦
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
sum = sum + ret;
}

printf("%d\n", sum);
return 0;
}

上面的代码虽然是对的但是依然不够高效,时间复杂度是O(N^2),那可不可以只利用一层循环就解决了呢?其实是可以的,因为上面进行了很多次重复计算。

如上面计算1!+2!+3!,就进行了很多次重复计算

//ret * 1
//ret * 1 * 2
//ret * 1 * 2 * 3

所以改写成高效的代码如下:

for(n = 1; n <= 3; n++)
{
//n*(n-1)! = n!
ret = ret * n;
sum = sum + ret;
}


【敲黑板】:当我们写出一个算法的时候,千万不要骄傲,好好想想怎么样才可以更加精炼,所以要多学多练!


加油加油!! 

零基础玩转C语言系列第三章——循环语句_i++_09



精彩评论(0)

0 0 举报