分支语句和循环语句


C语言是一种结构化的程序设计语言,所谓结构化就是三种结构:顺序结构,选择结构和循环结构。现在我们重点谈的是选择结构和循环结构。

要控制C语言的结构,需要用到控制语句,控制语句分为三大类,分支语句(if/else),循环语句(do while/while/for)和转向语句(break/go to/continue/return),括号中是他们都有特定的关键字。

1.分支语句(选择结构)

1. if/else类

if(条件)
  语句;//如果条件满足,执行语句,不满足,什么也不发生
if(表达式)
   语句;
else
   语句
if(表达式)
  语句一;
else if(表达式)
  语句二;
else
  语句三;

注:1.c语言没有18<=age<30的写法

2.if和else的匹配问题,else总是和最近的if匹配,使用{ }代码块提高代码风格,推荐书籍高质量c/c++编程

   代码练习1.判断奇数

#include<stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	if (n % 2)//n%2!=0  or n%2==1
	{
		printf("是奇数");
	}
	else
	{
		printf("不是奇数");
	}
}
代码练习2.输入1~100的奇数

#include<stdio.h>
int main()
{
	int i = 1;
	while (i <= 100)
	{
		if (i % 2)
		{
			printf("%d ", i);
		}
		i++;
	}
}
//这种方法是利用while循环产生1~100个数字,再判断,另一种方法是直接在循环体内i+=2

2.switch类

if/else的形式过于复杂,使用switch语句可以增加代码的可读性
适用于多分支,入口与情况相互匹配,入口决定从哪里进,break决定从哪里出,break根据需要加在适合的位置,

如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢? 你可以在语句列表中增加一条default子句,把下面的标签 default:
写在任何一个 case 标签可以出现的位置。 当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default子句后面的语句就会执行。所以,每个switch语句中只能出现一条default子句。
但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default子句

switch(入口:整型表达式)
{
    语句项;
}
//是一些case语句:
//如下:
case 情况:整形常量表达式:
    语句;

练习代码:输入几打印星期几

#include<stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	switch(n)
	{
	case(1):
		printf("周一\n");
		break;
	case(2):
		printf("周二\n");
		break;
	case(3):
		printf("周三\n");
		break;
	case(4):
		printf("周四\n");
		break;
	case(5):
		printf("周五\n");
		break;
	case(6):
		printf("周六\n");
		break;
	case(7):
		printf("周日\n");
		break;
	}
	return 0;
}

根据需要也可以让多条case语句合并,最后只执行一条语句

#include<stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	switch (n)
	{
	case(1):
	case(2):
	case(3):
	case(4):
	case(5):
		printf("工作日\n");
		break;
	case(6):
	case(7):
		printf("休息日\n");
		break;
	default:
		printf("输入错误\n");
		break;
	}
	return 0;
}

switch语句允许嵌套使用
看下面这段代码,结果是什么呢?

#include <stdio.h>

int main()
{
    int n = 1;
    int m = 2;
    switch (n)
    {
    case 1:
        m++;
    case 2:
        n++;
    case 3:
        switch (n)
        {//switch允许嵌套使用
        case 1:
            n++;
        case 2:
            m++; n++;
            break;
        }
    case 4:
        m++;
        break;
    default:
        break;
    }
    printf("m = %d, n = %d\n", m, n);
    return 0;
}

m = 5, n = 3

​2.循环语句

1.while循环

//while 语法结构
while(表达式)
 循环语句;

1.break介绍

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

这里代码输出的结果是什么? 1 2 3 4
总结:
break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。

2.continue介绍

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

这里代码输出的结果是什么?
1 2 3 4

//continue代码示例2
#include <stdio.h>
int main()
{
	int i = 1;
	while (i <= 10)
	{
		i = i + 1;	
			if (i == 5)
				continue;
		printf("%d ", i);
	}
	return 0;
}

这里代码输出的结果是什么?
2 3 4 6 7 8 9 10

总结: continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
while循环中的调整部分会让循环走到终止条件,如果continue跳过了调整部分则循环无法终止

3.多组输入之学习使用getchar()

getchar
int getchar ( void );
Get character from stdin
读取成功返回字符的ASCII码,读取失败返回EOF,本质为-1,
EOF - end of file 均为int类型(char存不下)
与之对应的是putchar(ch),Ctrl+Z可以使他读取失败返回EOF

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

会显示确认失败,原因是用户通过键盘输入12345之后,scanf会读取空格之前的,所以scanf在读取时不读取\n也不读取空格,getchar()发现缓冲区里面有东西就会读取,所以可以利用getchar()清空缓冲区,getchar()工作一次,缓冲区就会少一个字符

	//方法1
	getchar();//处理\n

	//方法2
	int tmp = 0;
	while ((tmp = getchar()) != '\n')
	{
		;
	}

利用循环的方法清空缓冲区,为了让用户输入Y/N时没有干扰

#include <stdio.h>
int main()
{
    char ch = '\0';
 while ((ch = getchar()) != EOF)
 {
     if (ch < '0'|| ch > '9')
        continue;
     putchar(ch);
 }
 return 0;
}
//这个代码的作用是:只打印数字字符,跳过其他字符的、
	int ch = 0;
	//可以持续输入,直到用户输入Ctrl+Z(VS下3次)
	while ((ch = getchar()) != EOF)
		putchar(ch);
	while (scanf("%d", &ch) != EOF)
		printf("%d ", ch);

注:在VS下测试的时候两种代码会有差别

4.for循环

for(表达式1; 表达式2; 表达式3)
 循环语句;

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

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

对于for循环的continue会来到调整部分,while会来到判断部分
相比while循环,for循环的三个必须条件很集中,查找修改方便。所以,for循环的风格更胜一筹;for循环使用的频率也最高。
for语句的循环控制变量
建议:

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

一些for循环的变种

#include <stdio.h>
int main()
{
 //代码1
 //for循环的判断部分省略了,就意味着判断恒为真
 for(;;)
 {
 printf("hehe\n");
 }
    //for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。
    
    //代码2
    int i = 0;
    int j = 0;
    //这里打印多少个hehe?
    for(i=0; i<10; i++)
   {
        for(j=0; j<10; j++)
       {
           printf("hehe\n");
       }
   }
    
    //代码3
    int i = 0;
    int j = 0;
    //如果省略掉初始化部分,这里打印多少个hehe?
    for(; i<10; i++)
   {
        for(; j<10; j++)
       {
           printf("hehe\n");
       }
   }
    
 //代码4-使用多余一个变量控制循环
 int x, y;
    for (x = 0, y = 0; x<2 && y<5; ++x, y++)
   {
        printf("hehe\n");
   }
 return 0;

1.打印100个hehe
2.10个hehe

//请问循环要循环多少次?
#include <stdio.h>
int main()
{
 int i = 0;
 int k = 0;
 for(i =0,k=0; k=0; i++,k++)
        k++;
 return 0;
}

0次

5.do…while()循环

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

循环至少执行一次,使用的场景有限,所以不是经常使用。
do…while();循环的break和continue与while很类似

3.练习使用分支语句和循环语句

1. 计算 n的阶乘。

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

2. 计算 1!+ 2!+ 3!+ …… + 10!

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

3.有序数组的二分查找

1.二分查找的思路
2.代码实现

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int n = 0;
	printf("请输入你要查找的数字");
	scanf("%d", &n);
	int left = 0;
	int right = sizeof(arr)/sizeof(arr[0])-1;
	while (left <= right)
	{
        int mid = left + (right - left) / 2;
		int mid = (left + right) / 2;
		if (arr[mid] < n)
		{
			left = mid + 1;
		}
		else if (arr[mid] > n)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标为%d", mid);
			return 0;
		}
	}
	printf("找不到");
	return 0;
}

4.字符向中间汇聚

//4. 编写代码,演示多个字符从两端移动,向中间汇聚。
//  hello world!!!
//  ##############
//  h############!
//  he##########!!
//       ……
//  hello world!!!

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

int main()
{
	char arr1[] = "hello world!!!";
	char arr2[] = "##############";
	int left = 0;
	int right = sizeof(arr1) / sizeof(arr1[0]) - 2;
	while (left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		left++;
		right--;
		Sleep(1000);
		system("cls");
	}
	printf("%s", arr2);
}

这里涉及到sizeof()和strlen()的问题,strlen需要include<string.h>,他是库函数,统计\0之前的字符串的长度(不含\0),sizeof()统计的是元素整个的大小,如果是字符串也会计算\0(含\0)

5.模拟用户登录

//5. 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则
//提示登录成,如果三次均输入错误,则退出程序。
#include<stdio.h>
#include<string.h>
int main()
{
	char psword[20] = { 0};
	printf("请输入密码");
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		scanf("%s", psword);
		char arr[] = "abcdef";
		if (strcmp(psword, arr) == 0)
		{
			printf("输入正确");
			return 0;
		}
		else
		{
			printf("重新输入");
		}
	}
	if (i == 3)
	{
		printf("三次均失败");
		return 0;
	}

}

在VS下,char psword[20] = {0};和char psword[20] = { };char psword[20]=" ";
psword里面的元素都被初始化为\0,ASCII码也是0 如果是’0’则是字符0,ASCII为48

6.猜数字游戏(分支与循环综合)

1.产生1~100的随机数
2.玩家猜(互动)
3.游戏可以一直玩,循环至少进入一次,考虑使用do…while();,用户选择不同数字对应不同的游戏结果,所以采用switch的分支语句

用C语言产生随机数的方法

int rand(void) 函数返回0~0X7FFF的数,也就是0至32767,如果使用 int ret=rand();,则每次产生一样的随机数,错误,在文档中对rand函数的说明中有 use the srand function to seed the psendorandom-number generator before calling rand,而文档对srand函数的解释是void srand(unsigned int seed),所以我们的思路是要给srand函数传一个随机数作为参数,这里可以想到时间作为一个一直变化的数字很适合,这里引入时间戳的概念,他是当前时间相较于计算机起始时间的差值,获取时间戳的方法是调用time函数,time函数可以返回一个时间戳
time_t time(time_t* timer) timer:storage location for time
如果要把时间戳存起来就要传一个地址给time函数,在外面创建一个time_t 类型的t变量,t的地址是time_t*类型的变量,然后把这个值传给timer,这样函数会把时间戳的值放进t,如果不想传,可以直接给NULL,该time函数会返回一个时间戳,只需要接收这个时间戳就可以,既可以把时间戳时间放进timer所指向的空间,也可以通过返回值

//调用time函数的方法:
 time_t t=time(NULL);
 time_t t;
 time(&t);

tips:time_t本质是一个整数,srand需要一个unsigned int 的整数作为参数,所以需要这样写

> srand((unsigned int)time(NULL));
> int ret=rand();

但是发现这样还是不够随机原因是每次调用一次srand,频繁生成起点,那么便不够随机,就好像每次随机数都要重新算,为了让srand函数只调用一次就把他放进主函数

代码实现

#include<time.h>
#include<stdio.h>
#include<stdlib.h>
void meau()
{
	printf("****** 猜数字游戏*******\n");
	printf("******按1进入游戏*******\n");
	printf("******按0退出游戏*******\n");

}
void game()
{
	int ret = rand()%101;//控制范围
	printf("请输入数字");
	int guess = 0;
	
	while (1)
	{
		scanf("%d", &guess);//这个要写在循环体内
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("猜对了\n");
			break;
		}
	}

}
int main()
{
	srand((unsigned int)time(NULL));
	int n = 0;
	do {
		 meau();
		scanf("%d", &n);
		switch (n)
		{
		case 1://玩游戏
			 game();
			break;
		case 0://退出游戏
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while(n);

	return 0;
}

7.goto语句介绍

C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。 从理论上
goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。 例如:一次跳出两层或多层循环。
多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环

//goto语言真正适合的场景如下:
for(...)
    for(...)
   {
        for(...)
       {
            if(disaster)
                goto error;
       }
   }
    …
error:
 if(disaster)
         // 处理错误情况

一个有趣的关机程序

while VS goto

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char s[20] = "";
	system("shutdown -s -t 60");
	while (1)
	{
		printf("输入我是猪,取消关机\n");
		scanf("%s", s);
		if (strcmp(s, "我是猪") == 0)
		{
			system("shutdown -a");
			break;
		}
		else
		{
			printf("重新输入\n");
		}	
	}
	return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char s[20] = "";
	system("shutdown -s -t 60");
again:
		printf("输入我是猪,取消关机\n");
		scanf("%s", s);
		if (strcmp(s, "我是猪") == 0)
		{
			system("shutdown -a");
		
		}
		else
		{
			goto again;
			printf("重新输入\n");
		}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值