[C语言]有关分支与循环的操作符

目录

1.关系操作符

2.条件操作符

3.逻辑操作符

3.1逻辑取反操作符!

3.2与运算符

3.3或运算符

3.4闰年的判断

4.5短路

4.补充:goto语句

5.猜数字游戏

5.1随机数的生成

5.1.1rand

5.1.2srand

5.1.3time

5.1.4设置随机数的范围

5.2猜数字游戏实现

5.2.1设计开始界面

5.2.2让程序先走起来

5.2.3猜数字的逻辑

5.2.4最终结果

5.2.5拓展:限定次数猜数字


1.关系操作符

        C语言用于比较的的表达式,称为“关系表达式”,其中使用的运算符就叫做“关系运算符”,主要有以下六个:

  • > 大于运算符
  • < 小于运算符
  • <= 小于等于运算符
  • >= 大于等于运算符
  • == 相等运算符
  • != 不相等运算符

        如下列举例

a == b;
a != b;
a < b;
a > b;
a <= b;
a >= b;

        关系表达式通常返回0来表示假,返回非零表示真。如9>8返回1,8>9返回0。

        关系表达式常用于if或while结构。

if(a==9)
{
    printf("%d is baka",a);
}

注意:相等运算符==和赋值运算符=是两个不一样的运算符,如果混淆可能会写出错误但是能运行,以至于不好发现错误的代码。

if(a=3)
{
    //...
}

        上面的代码,原意是a==3,但是不小心写成了a=3,这个式子表示对变量a赋值3,返回值为3,所以if的判断总是为真。

        为了防止这种错误的出现,咱们可以调换一下变量的位置,如下

if(3==a)
{
    //...
}

        如果这时候误把==写成了=,那么编译器就会报错,因为3是一个常数,不能给一个常数赋值。

注意:还有一个需要避免的错误:多个关系运算符不宜连用

i<j<k

        上面示例中,连续使用两个运算符,确实合法,不会报错,但是达不到想要的效果——j不一定在i和k的值之间——因为关系运算符从左向右计算,所以执行实际如下,

(i<j)<k

        i<j先一步返回0或者1,所以最终是0或1来和k进行比较。如果想要判断变量j在不在i和k之间,可以有以下写法。

//&&是逻辑运算符,下面会讲
i<j && j<k

        举个例子,通过年龄判断一个人是不是大学生

#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if (18 <= age <= 22)
	{
		printf("大概率是大学生\n");
	}
	return 0;
}

        如果按以上写法,当输入为10的时候,如下        

        输出仍为“大概率是大学生",就是因为先判断了18<=age返回了0,于是有0<=22的判断,返回了1,为真所以进入if语句进行打印。

        所以咱们应该把条件修改为如下

#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if (18 <= age && age <= 22)
	{
		printf("大概率是大学生\n");
	}
	return 0;
}

        剩下的操作符同理,按字面意思使用即可。

2.条件操作符

        条件操作符也叫做三目操作符,需要接受3个操作数,如下

exp1 ? exp2 : exp3

        条件操作符的计算逻辑是:如果 exp1 为真, exp2 计算,计算的结果是整个表达式的结果;如果 exp1 为假, exp3 计算,计算的结果是整个表达式的结果。

        也就是说条件操作符能在一定程度上代替if语句,从而使代码简洁。

#include <stdio.h>
int main()
{
	size_t a;
	scanf("%zd", &a);
	if (a > 0)
	{
		a *= 2;
	}
	else
	{
		a = 4;
	}
	printf("%zd", a);

	return 0;
}

        如上代码,输入一个a,如果a为0则赋值为4,否则a变为原来的两倍。现在,把上面的代码用三目运算符来实现。如下

#include <stdio.h>
int main()
{
	size_t a;
	scanf("%zd", &a);
	a = a == 0 ? 4 : 2 * a;
	printf("%zd", a);
	return 0;
}

        再比如,找到两个数之间的较大值,如下,这种时候使用看起来比if语句少很多行。

#include <stdio.h>
int main()
{
	int a = 9;
	int b = 10;
	int max;
	max = a > b ? a : b;
	return 0;
}

3.逻辑操作符

        逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有以下三个运算符

  • ! 逻辑取反运算符(改变单个表达式的真假)
  • && 逻辑与运算符,就是并且的意思(两侧都为真则表达式为真,否则为假)
  • || 逻辑或运算符,就是或者的意思(两侧有一个真则表达式为真,否则为假)

:C语言中,非0表示真,0表示假

3.1逻辑取反操作符!

a!a
非00
01

        比如,咱们有个变量叫flag,如果flag为假,就要做点什么,那么就可以这么写

#include <stdio.h>
int main()
{
	int flag = 0;
	if (!flag)
	{
		printf("do something that is dull");
	}
	return 0;
}

        如果flag为真,那么!flag为假,如果flag为假,!flag为真,所以上面的代码的意思就是flag为假,执行if语句中的代码。

3.2与运算符

a      b      a&&b
非0非01
非000
0非00
000

        &&为与运算符,也就是并且的意思,&&是一个双目运算符,使用方式就是a&&b,&&表达式两边表达式都为真时,整个表达式才为真,只要有一个假,那么就是假。

        比如,3月到5月是春天,用代码表示就下,

#include <stdio.h>
int main()
{
	int month;
	scanf("%d", &month);
	if (month >= 3 && month <= 5)
	{
		printf("春天来了!");
	}
	return 0;
}

        这里的表达式意思就是month既要大于等于3也要小于等于5,必须同时满足。

3.3或运算符

a   b   a||b
非0非01
非001
0非01
000

        ||就是或运算符,也就是或者的意思,||是一个双目运算符,使用方法是a||b,||两边的表达式只要有一个是真,整个表达式就是真,两边表达式为假的时候,才为假。

        比如,用代码来表现,一年中月份是12月或者1月或者2月是冬天,

#include <stdio.h>
int main()
{
	int month;
	scanf("%d", &month);
	if (month==12||month==1||month==2)
	{
		printf("冬天!");
	}
	return 0;
}

3.4闰年的判断

        现要求,输入应该年份year,判断year是否为闰年。

        闰年的判断规则(两条规则满足其一即可):

  1. 能被4整除并且不能被100整除
  2. 能被400整除
#include <stdio.h>
int main()
{
	int month;
	scanf("%d", &month);
	if (month % 400 == 0 || (month % 4 == 0 && month % 100 != 0))
	{
		printf("是闰年\n");
	}
	else
	{
		printf("不是闰年\n");
	}
	return 0;
}

4.5短路

        C语言逻辑运算符还有一个特点,它总是对左侧的表达式求值,再对有点的表达式求值,这个顺序是保证的。

        如果左边的代码表达式满足逻辑运算符的条件,就不再对右边的表达式求值,这种情况就称之为“短路”。

        对于前面的代码

if(month >= 3 && month <= 5)

        左操作数为month>=3,有操作数为month<=5,当左操作数的结果是0的时候,即使不判断month<=5,整个表达式的结果也是0。

        所以对于&&操作符来说,左边的操作数的结果为0时,右边的操作数就不执行。

        那么对于||操作符有事怎样的呢?再来看看前面的代码

if(month == 12 || month==1 || month == 2)

        r如果month==12,则不用在判断month是否等于1或2,整个表达式的结果也是1。

        所以,||操作符的左操作数的结果不为0时,就无需执行右操作数。

        以上这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进行计算的运算称为短路求值

4.补充:goto语句

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

#include <stdio.h>
int main()
{
	printf("cirno\n");
	goto lake;
	printf("baka");
lake:
	printf("skip baka");
	return 0;
}

        goto语句使用不当的话会导致函数在内部胡乱跳转,打乱程序的执行流程,所以能少用就少用。但是goto也并非一无是处,在多层循环的代码中,如果想要快速跳出,使用goto就非常方便了。如下,

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

5.猜数字游戏

        有了前面的一些知识,就可以开始写一些有趣的代码了,比如写一个猜数字游戏

        游戏要求:

  1. 电脑自动生成1~100的随机数
  2. 玩家猜数字,猜数字的过程中,根据猜测的大小给出大了或者小了的反馈,直到猜对为止。

5.1随机数的生成

        想要完成猜数字游戏,首先得产生随机数,那么怎么产生随机数呢?

5.1.1rand

        C语言提供了一个函数,叫rand,需要包含头文件stdlib.h,这函数是可以生成随机数的,原型如下

int rand (void);

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

        来测试一下rand吧,

int main()
{
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
	printf("%d\n", rand());
    return 0;

}

        可以看到以下输出,结果很随机了

        再运行一次呢?

        一模一样耶!其实rand生成的随机数是伪随机,也就不是真正的随机数,而是通过某种算法生成的随机数。真正的随机数是无法预测下一个值是多少的。而rand函数是对一个叫做“种子”的基准值进行运算生成的随机数。

        之所以前面每次运行的结果相同吗,是因为rand函数生成随机数的默认种子是1。

        所以,想要生成不同的随机数,就是要让种子变化。

5.1.2srand

        C语言又提供了一个函数叫srand,同样需要包含头文件stdlib.h。这个函数是用来初始化随机数的生成器,原型如下,

void srand (unsigned int seed);

        程序在调用rand之前,会先调用srand函数,通过srand函数的参数seed来设置rand函数生成的随机数时需要的种子,只要种子在变化,每次生成的随机数序列就变化起来了。

        也就是说,只要让srand函数的参数是随机的,rand就能生成随机数,但是生成一个随机数就需要一个随机数,不是很矛盾吗?

5.1.3time

        在程序中,咱们一般是使用程序运行的时间作为种子的,因为时间时刻在变化。

        在C语言中有一个函数,叫time,需要包含头文件time.h,就可以获得这个时间,以下为time原型

time_t time (time_t* timer);

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

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

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

        这时候就可以改写生成随机数的代码,

int main()
{
    //time返回值用于设置种子
    //strand接受的是unsigned  int类型的参数,所以要强制类型转换
	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函数是不需要频繁调用的,一次运行程序中调用一次就够了。

5.1.4设置随机数的范围

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

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

        如果要生成1~100之间的随机数,方法如下,

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

        如果要生成100~200的随机数,方法如下,

100 + rand()%(200-100+1)//余数范围为0~100

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

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

5.2猜数字游戏实现

5.2.1设计开始界面

        游戏开始,需要有引导来确保输入正确,以至于游戏能够正常开始。

        设计的显示开始界面的函数如下

void menu()
{
	printf("***********************\n");
	printf("*****   1.game   ******\n");
	printf("*****   2.quit   ******\n");
	printf("***********************\n");
	printf("请输入数字:>");
}

5.2.2让程序先走起来

        先不管怎么猜,先让咱们的输入输出有回应,

int main()
{
    //设置随机数种子
	srand((unsigned int)time(NULL));
    //通过输入a来开始
	int a = 0;
    //打印开始界面
	menu();
    //正常输入则进入循环
	while (scanf("%d", &a) != EOF)
	{
		switch (a)
		{
		case 1:
		{
			printf("游戏开始,请输入一个数字\n");
			//这里是还未实现的猜数字游戏函数
		}
		case 2:
        {
	        printf("游戏结束\n");
	        break;
        }
        //出现1和2之外的数据则重新输入
		default: printf("输入错误请重新输入\n");

		}
        //游戏结束
		if (a == 2) break;
	}
    return 0;
}

        以上,先打印开始界面,通过用户的输入,来走switch的三种情况,即1开始游戏,2结束游戏,3重新输入。当游戏猜完结束时,再一次对a输入从而进行下一把,或者结束。

        上述代码运行如下,

        当输入1时,

        但是这时候,还没有游戏函数,所以先来重新输入。这次输入2,

        再来输入1和2之外的数试试。此时提醒重新输入。

5.2.3猜数字的逻辑

        猜数字需要做的,范围内设置好的数字

        范围内的数字就很好设置了

int num = 0;
//数字在1~100
num = 1 + rand() % 100;

        那么猜就要靠用户输入了,需要循环来保证持续的输入,需要判断大小来给出合理的提示,猜完之后需要弹出菜单来指引下一步操作。

int cai = 0;
//先让循环走起来,通过break来退出
while (1)
{
    //用户输入cai
	scanf("%d", &cai);
    //cai来和目标num比较,cai大则说明猜大了
	if (cai > num)
	{
		printf("猜大了\n");
	}
    //cai比num小,说明猜小了
	else if (cai < num)
	{
		printf("猜小了\n");
	}
    //否则就是猜中了,此时break退出循环
	else
	{
		printf("恭喜你猜对了!\n");
		break;
	}

}
//游戏结束,弹出菜单来引导继续或者结束
menu();

        将两份代码结合成一个函数

void guess()
{
	int num = 0;
	num = 1 + rand() % 100;
	int cai = 0;

	while (1)
	{
		scanf("%d", &cai);

		if (cai > num)
		{
			printf("猜大了\n");
		}
		else if (cai < num)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你猜对了!\n");
			break;
		}

	}
	
	menu();

}

5.2.4最终结果

        以下是最终代码

int main()
{
	srand((unsigned int)time(NULL));
	int a = 0;
	menu();
	while (scanf("%d", &a) != EOF)
	{
		switch (a)
		{
		case 1:
		{
			printf("游戏开始,请输入一个数字\n");
            //参见上方代码
			guess();
			break;
		}
		case 2:
		{
			printf("游戏结束\n");
			break;
		}
		default: printf("输入错误请重新输入\n");

		}
		if (a == 2) break;
	}
    return 0;
}

5.2.5拓展:限定次数猜数字

        如果想要增加限制,在五次之内猜出数字,该怎么修改代码呢?

        其实需要做的只是添加计数,修改循环条件,顺带修改一下输入数字后的提示,以下是对游戏函数的修改。

void guess_count()
{
	int num = 0;
	num =1+ rand()%100;
	int cai = 0;
    //增加计数,设定为5
	int count = 5;
	//循环条件修改为count
	while(count)
	{
		scanf("%d", &cai);

		if (cai > num)
		{
            //每猜一次都--count,并修改游戏提示
			--count;
			printf("猜大了,还有%d次机会\n", count);
		}
		else if (cai < num)
		{
			--count;
			 printf("猜小了,还有%d次机会\n", count);
		}
		else
		{
			printf("恭喜你猜对了!\n");
			break;
		}
		
	}
    //出循环有两个条件:break、count==0,所以要进行判断是否提示
	if (count == 0)
	{
		printf("机会用完了,再试一次吧!\n");
	}
	menu();
	
}

        最后只需要把上面的函数替换掉主函数中的guess函数就可以了。

评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值