> 文章列表 > C learning_8

C learning_8

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-32767int 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-1int 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-1int 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-1int 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;
}