C learning_8

猜数字游戏

猜数字游戏:

        1.电脑会随机产生一个数

        2.猜数字

                a>猜大了,提醒猜大了,继续猜

                b>猜小了,提醒猜小了,继续猜

                c>猜对了,恭喜你,猜对了,游戏结束

        3.玩完之后可以继续玩,不想退出程序

首先我们要完成这个游戏,就必须要生成一个随机数,接下来看看生成随机数的函数

 rand()函数,生成一个伪随机数,参数是void,返回值是int类型,使用时需要引用头文件<stdlib.h>,它的作用是生成一个范围在0和RAND_MAX之间的随机整数,其中RAND_MAX是一个常量,通常其值是32767。每次调用rand()函数时,将返回一个新的随机数。接下来我们用它来形成三个随机函数。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int i = 0;
    for(i=0;i<3;i++)
    {
        int randomNumber = rand();
        printf("%d\n", randomNumber);
    }
    return 0;
}

 我将该程序运行了三次,发现生成的随机数一样,为什么呢?

此时我们就要注意上面加粗的字体——伪随机数

        rand函数生成的随机数序列是伪随机数序列,而不是真正的随机数序列,因此每次生成的随机数序列都是相同的。这是因为rand函数使用的是一种叫做线性同余算法的伪随机数生成方式,它是基于计算机的固有特性(如时钟周期、操作系统的种子等)生成的,因此每次运行程序所生成的随机数序列都是相同的。

        为了避免生成的随机数序列每次都相同,可以使用srand函数来初始化随机数种子,从而改变生成的随机数序列,接下来我们来看看srand函数。

 srand函数,设置一个随机的起始点,参数是无符号整型(unsigned int),无返回值,使用时需要引用头文件<stdlib.h>,srand函数是C语言标准库中的一个随机数种子初始化函数,用于初始化随机数序列。

其原型时是:

void srand(unsigned int seed);

在使用rand函数生成随机数之前,需要先调用srand函数来设置随机数种子,以确保每次运行程序生成的随机数序列都是不同的。

当我们使用函数srand分别传入1,2,3就可以显示不同的随机数了

 但是我们生成随机数希望可以自己变化,而不是我们手动去设置它才能变化,因此我们要设置一个随机种子,但是我们原来就是想生成一个随机数,现在又要生成一个随机种子,那这样不是矛盾了吗?其实不然,我们发现时间每时每刻都在变化,所以我们可以用时间戳来设置这个随机种子,这是我们首先就需要了解时间戳的概念。

 时间戳

        时间戳(Timestamp)是指某个特定时间点所对应的数字,通常是一个整数。在计算机中,时间戳通常是指自某个特定时间开始(例如:1970年1月1日0点0分0秒)到当前时刻所经过的秒数(称为Unix时间戳),也可以是毫秒数、微秒数等其他时间单位。 时间戳通常用于记录和表示某个事件发生的时间,它不受时区的影响,因此具有很高的精度和通用性。在编程中,常常会用时间戳来对不同的事件进行排序、计算时间差、生成随机数种子等操作。

 所以这时我们就要获取计算机的时刻,就要用到time函数。

         time函数是C语言标准库中用于获取当前系统时间的函数,

其原型为:

time_t time(time_t *tloc);

time函数返回当前的系统时间,并以time_t类型的值表示(time_t是C语言标准库中用于表示时间的数据类型)。如果参数不为NULL,则time函数也会将当前时间存储到该指针指向的变量中。 time函数返回的时间表示自1970年1月1日0时0分0秒起至当前时间所经过的秒数,因此也被称为Unix时间戳。time函数可以用于获取当前系统时间,计算时间差,确定随机数种子等操作。

这里注意一个小细节,由于srand()函数的参数是(无符号整型)unsigned int,time函数的返回值是time_t,所以我们需要将time函数的返回值进行强制类型转换:

srand((unsigned int)time(NULL));

 这时我们发现,使用时间戳作为随机种子后,我们生成的随机数就都不一样了。

为了使游戏的难度降低,我们想要生成1-100之间的数,我们就需要使用下面的方法就可以生成啦

rand()%100+1;

接下来,我们来看完整的猜数字游戏的代码

//猜数字游戏
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void menu()
{
	printf("****************************\n");
	printf("******1.paly    0.exit******\n");
	printf("****************************\n");

}
void game()
{
	//1.生产随机数
	//srand((unsigned int)time(NULL));//要给srand传递一个变化的值,\
                                计算机上的时间是时刻发生变化的
	//srand( unsigned int seed )
	//time函数可以返回一个时间戳 - time_t
	//rand();//生产随机数,随机数范围0-32767
	int ret = rand() % 100 + 1;//生产随机数,随机数范围1-100
	//printf("%d", ret);
	//2.猜数字
	int guess = 0;
	while(1)
	{
		printf("请猜数字:>");
		scanf("%d", &guess);
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你,猜对了\n");
			break;
		}
	}
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	//打印菜单
	//1.玩游戏
	//2.退出游戏
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("猜数字游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);
	
	return 0;
}

想体验的小伙伴,可以亲自去尝试一下哟。

goto语句

        C语言中提供了可以随意滥用的 goto语句和标记跳转的标号,但是只能在当前函数内跳转,不能跨越多个函数进行跳转。

        goto语句是一条跳转语句,可用于将程序的执行从一段代码直接跳转到其他代码的特定位置。它可以在程序的任何地方使用,但过度使用goto语句可能导致代码难以理解和维护。 在使用goto语句时,需要定义一个标签,用于标示跳转的目标位置。例如,如果有一段代码需要重复执行多次,可以在代码块的开头定义一个标签,并在代码块的末尾通过goto语句跳转到该标签的位置,从而实现代码块的循环执行。

例如,下面是一个使用goto语句实现循环的示例代码:

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

        在这个示例代码中,我们定义了一个标签LOOP,并使用goto语句在代码块的末尾跳转到该标签的位置。在每次执行该代码块时,程序都会按照顺序执行代码,直到满足if语句的条件时跳转到标签LOOP的位置,然后重新开始执行代码块,实现了代码块的循环执行,直到i的值达到10为止。

        过度使用goto语句可能导致代码难以理解和维护,但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过 程。 例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。

for (...)
for (...)
{
    for (...)
    {
        if (disaster)
            goto error;
    }
}
error :
if (disaster)
// 处理错误情况

关机程序

        1.程序运行起来,将会在一分钟内关机

        2.如果输入1,我们就取消关机

        这里我们首先介绍一个关机的命令:shutdown

         Windows 系统自带一个名为Shutdown.exe的程序,可以用于关机操作(位置在Windows\System32下),一般情况下Windows系统的关机都可以通过调用程序 shutdown.exe来实现的,同时该程序也可以用于终止正在计划中的关机操作。

//关机程序
// 1.程序运行起来,将会在一分钟内关机
// 2.如果输入1,我们就取消关机
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int input = 0;
	//程序关机倒计时
again:
	system("shutdown -s -t 60");
	printf("请注意,你的电脑将在1分钟内关机,如果输入1,就会取消关机\n");
	scanf("%d", &input);
	if (input == 1)
	{
		system("shutdown -a");
	}
	else
	{
		goto again;
	}
	return 0;
}

system("shutdown -s -t 60");

        `system("shutdown -s -t 60")` 是一个 `system()` 函数的调用,它的作用是在调用这个函数的程序中执行一条系统命令。 在这个特定的例子中,系统命令是 `shutdown`,它是 Windows 操作系统的一个命令,可以用来关机、重启、注销等等。 `-s` 选项表示关机,`-t 60` 表示在60秒后关机。 因此,这行代码的意思是让执行这个程序的电脑,在运行程序后的60秒内关机。

system("shutdown -a");

        `system("shutdown -a")` 是一个 `system()` 函数的调用,它的作用是在调用这个函数的程序中执行一条系统命令。 在这个特定的例子中,系统命令是 `shutdown`,它是 Windows 操作系统的一个命令,可以用来关机、重启、注销等等。 `-a` 选项表示取消之前已经发出的关机、重启等命令。 因此,这行代码的意思是让执行这个程序的电脑,取消之前已经设定的关机命令。

而如果不适用goto语句,则可以使用循环:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int input[10] = 0;
    system("shutdown -s -t 60");
    while (1)
    {
        printf("电脑将在1分钟内关机,如果输入:1,就取消关机!\n请输入:>");
        scanf("%d", &input);
        if (1 == input)
        {
            system("shutdown -a");
            break;
        }
    }
    return 0;
}

素数的求解的n中境界
 

思路:
        素数:即质数,除了1和自己之外,再没有其他的约数,则该数据为素数,具体方式如下

//方法一:试除法
int main()
{
	int i = 0;
	int count = 0;


    // 外层循环用来获取100~200之间的所有数据,100肯定不是素数,因此i从101开始
	for(i=101; i<=200; i++)
	{
		//判断i是否为素数:用[2, i)之间的每个数据去被i除,只要有一个可以被整除,则不是素数
		int j = 0;
		for(j=2; j<i; j++)
		{
			if(i%j == 0)
			{
				break;
			}
		}
        
		// 上述循环结束之后,如果j和i相等,说明[2, i)之间的所有数据都不能被i整除,则i为素数
		if(j==i)
		{
			count++;
			printf("%d ", i);
		}
	}


	printf("\ncount = %d\n", count);
	return 0;
}


//上述方法的缺陷:超过i一半的数据,肯定不是i的倍数,上述进行了许多没有意义的运算,因此可以采用如下
// 方式进行优化
// 方法二:每拿到一个数据,只需要检测其:[2, i/2]区间内是否有元素可以被2i整除即可,可以说明i不是素数
int main()
{
	int i = 0;//
	int count = 0;


	for(i=101; i<=200; i++)
	{
		//判断i是否为素数
		//2->i-1
		int j = 0;
		for(j=2; j<=i/2; j++)
		{
			if(i%j == 0)
			{
				break;
			}
		}
		//...
		if(j>i/2)
		{
			count++;
			printf("%d ", i);
		}
	}


	printf("\ncount = %d\n", count);
	return 0;
}




/*
方法二还是包含了一些重复的数据,再优化:
如果i能够被[2, sqrt(i)]之间的任意数据整除,则i不是素数
原因:如果 m 能被 2 ~ m-1 之间任一整数整除,其二个因子必定有一个小于或等于sqrt(m),另一个大于或等于 sqrt(m)。
*/
int main()
{
	int i = 0;
	int count = 0;


	for(i=101; i<=200; i++)
	{
		//判断i是否为素数
		//2->i-1
		int j = 0;
		for(j=2; j<=sqrt(i); j++)
		{
			if(i%j == 0)
			{
				break;
			}
		}
		//...
		if(j>sqrt(i))
		{
			count++;
			printf("%d ", i);
		}
	}


	printf("\ncount = %d\n", count);
	return 0;
}


//方法4
/*
继续对方法三优化,只要i不被[2, sqrt(i)]之间的任何数据整除,则i是素数,但是实际在操作时i不用从101逐渐递增到200,因为出了2和3之外,不会有两个连续相邻的数据同时为素数
*/


int main()
{
	int i = 0;
	int count = 0;


	for(i=101; i<=200; i+=2)
	{
		//判断i是否为素数
		//2->i-1
		int j = 0;
		for(j=2; j<=sqrt(i); j++)
		{
			if(i%j == 0)
			{
				break;
			}
		}
		//...
		if(j>sqrt(i))
		{
			count++;
			printf("%d ", i);
		}
	}

	printf("\ncount = %d\n", count);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_64446981/article/details/130268241