初阶C语言-分支和循环语句(下)
“花会沿途盛开,以后的路也是。” 今天我们一起来继续学完分支语句和循环语句。
分支和循环
- 3.循环语句
- 3.4 do...while()循环
- 3.4.1 do语句的用法
- 3.5关于循环的一些练习
- 3.6 goto语句
3.循环语句
3.4 do…while()循环
3.4.1 do语句的用法
do循环语句;//当循环语句不止一句的时候,要用大括号括起来
while(表达式);
在前面,我们学过了用while循环和for循环在屏幕上打印1~10的数字,那么在do...while()循环中,如何实现这步操作呢?
#include <stdio.h>
int main()
{int i = 1;do{printf("%d ", i);i++;} while (i <= 10);return 0;
}

接下来,让我们用一张图了解一下do...while()循环的执行流程:

do语句的特点:循环至少执行一次,使用的场景有限,所以不是经常使用。
同样的,在do…while()循环中,也存在break和continue语句。接下来,让我们用示例看看用法是否一致?
#include <stdio.h>
int main()
{int i = 1;do{if (i == 5)break;//遇到break循环终止,因此屏幕上只打印出1~4printf("%d ", i);i++;} while (i <= 10);return 0;
}

#include <stdio.h>
int main()
{int i = 1;do{if (i == 5)continue;//遇到continue,跳过本次循环后面的代码printf("%d ", i);i++;} while (i <= 10);return 0;
}
通过运行,我们可以发现程序进入了死循环,光标在4的后面一直闪烁。

总结:
do...while循环中的break和continue和在while循环中一模一样。break都是用来终止循环的,continue是跳过本次循环后面的代码,直接去判断部分。
3.5关于循环的一些练习
下面让我们一起下一些关于循环的练习:
1.计算n的阶乘
//计算n的阶乘
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int n = 0;int i = 0;int ret = 1;scanf("%d", &n);for (i = 1; i <= n; i++)//循环产生1~n的数字{ret = ret * i;}printf("n! = %d", ret);
}

2.计算1!+2!+3!+4!+5!+6!+7!+8!+9!+10!
//计算1!+2!+3!+4!+5!+6!+7!+8!+9!+10!
#include <stdio.h>
int main()
{int n = 0;int i = 0;int ret = 1;int sum = 0;for (n = 1; n <= 10; n++){ret = 1;//要让ret每次都从1开始for (i = 1; i <= n; i++)//循环产生1~n的数字{ret = ret * i;}sum = ret + sum;}printf("%d\n", sum);return 0;
}

我们可以发现,这段代码相对来说还是比较复杂的,每次都得先把n!算出来,然后在相加,每次都要从1开始乘到n,但实际上我们可以发现后一个数的阶乘等于前一个数的阶乘乘以这个数本身就行了,这样一来,简化了计算过程。那么,我们一起把代码优化一下吧!
#include <stdio.h>
int main()
{int i = 0;int ret = 1;int sum = 0;for (i = 1; i <= 10; i++){ret = ret * i;sum = ret + sum;}printf("%d\n", sum);return 0;
}

我们可以发现,这两段代码的结果相同,后者更优!因此,我们在写代码的时候,不光要看怎么能写出代码,还需要思考怎么样写才是最简便的。
3.在一个有序数组中查找具体的某个数字n,如果有,打印出它的下标,没有的话,给出提示。
当我们看到这个题目的第一眼,可能大多数人的想法就是从左向右一个一个寻找,找到的话就打印出下标,找不到就给出提示,这种方法我们也叫做遍历查找。假设我们要从1~10的十个数中找出6,那么该如何写这段代码呢?
//假设我们要从1~10的十个数中找出6,那么该如何写这段代码呢?有的话给出下标,没有的话给出提示
#include <stdio.h>
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int n = 0;int flag = 0;scanf("%d", &n);for (int i = 0; i <= 9; i++){if (arr[i] == n){printf("找到了,下标是: % d", i);flag = 1;break;}}if (flag == 0){printf("没找到!\n");}return 0;
}


虽然这种方法实现了我们想要的结果,但是我们发现这种算法比较复杂,如果我们现在要寻找的是10.那么这个循环将要走10次,那么如果是一个更大的数呢?比方说:妈妈带着小明去买了一双鞋,小明说这双鞋在600元以内,那么这个时候让我们来猜这双鞋是多少钱,难道我们需要从1开始一直查找到600吗?显然,计算量是相当大的,对于这种有序数组中某个元素的查找,我们这个给大家介绍一个新的方法,叫做折半查找,又称二分法。 下面,我们给出用二分查找解决上述问题的示例先帮助大家了解一下二分查找的过程。

我们可以发现
二分查找的效率很高,但是条件苛刻,只针对有序的数组中。
下面,我们给出详细代码:
//二分查找
#include <stdio.h>
int main()
{int left = 0;int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int right = sizeof(arr)/sizeof(arr[0])-1; //sizeof(arr)算的是数组的总大小,单位是字节int mid = 0;int flag = 0;int n = 0;scanf("%d", &n);while (left <= right){mid = (right + left)/2;if (arr[mid] == n){printf("下标为:%d", mid);flag = 1;break;}else if (arr[mid] > n){right = mid - 1;}else if (arr[mid] < n){left = mid + 1;}}if (flag == 0){printf("没找到!\n");}return 0;
}


4.编写代码,演示多个字符从两端移动,向中间汇聚。
假设我们这里需要实现Hello C World !!!的字符从两端移动,往中间汇聚,该如何实现呢?
#define _CRT_SECURE_NO_WARNINGS 1
//编写代码,演示多个字符从两端移动,向中间汇聚。Hello C World !!!!!!
#include <stdio.h>
#include <string.h>//使用strlen需要添加的头文件
#include <windows.h>//使用system("cls");需要添加的头文件
int main()
{char arr1[] = "Hello C World !!!!!!";char arr2[] = "********************";int left = 0;int right = strlen(arr2) - 1;//此时是数组元素是字符串,而不是一个个字符,通过前面的学习我们知道了字符串结束标志为'\0',但strlen计算的是除了'\0'以外的字符长度,因此-1即得到最右边数组的下标//int right = sizeof(arr2) / sizeof(arr2[0]) - 2;当然使用sizeof也是可以的,不过此时我们要进行减2的操作while (left <= right){arr2[left] = arr1[left];arr2[right] = arr1[right];printf("%s\n", arr2);Sleep(1000);//等待1秒system("cls");//清空屏幕left++;right--;}printf("%s\n", arr2);return 0;
}
5.编写代码实现,模拟用户登录情景,并且只能登录三次(如果正确,显示登录成功,如果错误,退出程序。)
//编写代码实现,模拟用户登录情景,并且只能登录三次(如果正确,显示登录成功,如果错误,退出程序。)
#include <stdio.h>
#include <string.h>//strcmp需要包含该头文件
int main()
{char arr[20] = { 0 };char password[] = "123456";int i;for (i = 0; i < 3; i++){printf("请输入密码:>");scanf("%s", arr);//strcmp函数是比较字符串的大小,如果>,则返回>0的值,如果<,则返回<0的值,如果相等,则返回0if (strcmp(arr, password) == 0){printf("登录成功!\n");break;}elseprintf("密码错误!\n");}if (i == 3){printf("三次密码均输入错误,退出程序!\n");}return 0;
}



6.猜数字游戏-电脑随机产生1~100之间的一个数,接下来,我们猜数字,如果小了,我们给出提示猜小了,如果猜大了我们给出提示猜大了,如果猜对了,那么恭喜你猜对了,游戏结束。
这里,我们需要先给大家介绍一下产生随机数的函数rand()

上述资料中,我们知道想要使用rand()函数,我们需要添加头文件#include <stdlib.h>我们可以先通过简单的代码看看rand()的功能
#include <stdio.h>
#include <stdlib.h>
int main()
{int ret = rand();printf("%d", ret);return 0;
}

经过调试运行,我们发现rand()确实能够产生一个随机数,但是多次调试我们又发现,每次产生的随机数都是41,那这就不能达到我们期望的结果。
查阅资料,我们可以发现
rand()函数是通过某种算法生成的随机数,因此它还不够随机,不能达到我们预期的结果。rand()函数生成的是伪随机数,且其生成的随机数的范围是:0~RAND_MAX. 通过查找我们可以发现RAND_MAX的值为32767。rand()函数在生成随机数之前,需要通过srand()函数设置随机数的生成器。

大家肯定又在想srand()函数又是干什么的呢?这里,我们带大家一起了解一下:

下面我们通过代码给大家进行演示:
#include <stdio.h>
#include <stdlib.h>
int main()
{srand(1);//srand(2);int ret = rand();printf("%d", ret);return 0;
}


我们可以发现
rand()是一个产生随机数的函数,而srand是一个设置随机数种子的函数,通常这两个函数是一起使用的,来完成产生随机数的功能。srand函数通过参数seed来改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,从而实现真正意义上的“随机”。
这里,我们介绍一下时间戳,通过百度,我们可以对时间戳有所了解:

我们可以发现,只要时间在变化,那么其所对应的时间戳就在变化,那么我们如何在C语言中获得时间戳呢,这里我们需要给大家介绍一下time()函数。

我们可以发现time()函数还存在一个参数,会返回时间戳,但是它的参数是一个指针,我们可以通过参数带回时间戳,这里我们不想用的话,可以用NULL(0)这个空指针来代替。我们发现time()函数的类型是time_t,但是srand()所需类型是unsigned int,这里我们就可以进行强制类型转换。
srand((unsigned)time(NULL));
这条指令的意思是利用系统时间来初始化系统随机数的种子值,使得每次运行由于时间不同产生而产生不同的随机数序列。如果想在一个程序中生成随机数序列,只需要在主程序开始处调用
srand((unsigned)time(NULL));后面直接用rand()函数就可以了。
接下里,我们就一起来写一下猜数字的游戏吧!
//猜数字游戏
#include <stdio.h>
#include <stdlib.h>//srand()函数和rand()函数所需要的头文件
#include <time.h>//time()函数所需要的头文件
void menu()
{printf("********************************\n");printf("********** 1.play **********\n");printf("********** 0.exit **********\n");printf("********************************\n");
}
//1.生成1~100的随机数
//2.猜数字
void game()
{int guess = 0;int ret = rand() % 100 + 1;//生成1~100的随机数,任何一个数%100等于0~99,加上1,就是1~100.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));//利用系统时间来初始化系统随机数的种子值,使得每次运行由于时间不同产生而产生不同的随机数序列。do {menu();printf("请选择:>");scanf("%d", &input);switch (input){case 0:printf("game over!\n");break;case 1:printf("game start!\n");game();break;default:printf("选择错误,请重新选择!\n");break;}} while (input);return 0;
}
3.6 goto语句
C语言中,提供了可以随意滥用的
goto语句和标记跳转的标号。从理论上goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。但在某种场合下,goto语句还是用得着的,最常见的用法就是终止程序在某种深度嵌套的结构的处理过程。例如:一次跳出两层或多层循环。多层循环这种情况使用break是达不到目的的,它只能从最内层循环退出到上一层循环。
goto语言真正适合的场景如下:
for(...)for(...){for(...){if(disaster)goto error;}}...
error:if(disaster)//处理错误情况
下面呢,我们给出goto语句的示例:
//goto语句
#include <stdio.h>
int main()
{printf("hehe!\n");printf("haha!\n");goto end;printf("heihei!\n");
end:printf("hihi!\n");return 0;
}

注:
goto函数只能在同一个函数内部跳转,不能跨函数
下面,我们也给出一个用goto语句写出关机程序的例子:(该程序仅供学习使用,不要过度整蛊同学!)
//关机程序
#include <stdio.h>
int main()
{char input[10] = { 0 };system("shutdown -s -t 60");
again:printf("你的电脑将在1分钟内关机,如果输入:我是猪,则可以取消关机程序!\n");scanf("%s", input);if (strcmp(input, "我是猪") == 0){system("shutdown -a");printf("关机程序已经取消!\n");}elsegoto again;return 0;
}



好啦,关于分支和循环到这里就完结啦,欢迎大家关注、点赞和评论!
相关文章:
初阶C语言-分支和循环语句(下)
“花会沿途盛开,以后的路也是。” 今天我们一起来继续学完分支语句和循环语句。 分支和循环 3.循环语句3.4 do...while()循环3.4.1 do语句的用法 3.5关于循环的一些练习3.6 goto语句 3.循环语句 3.4 do…while()循环 3.4.1 do语句的用法 do循环语句;//当循环语句…...
pytorch工具——pytorch中的autograd
目录 关于torch.tensor关于tensor的操作关于梯度gradients 关于torch.tensor 关于tensor的操作 x1torch.ones(3,3) xtorch.ones(2,2,requires_gradTrue) print(x1,\n,x)yx2 print(y) print(x.grad_fn) print(y.grad_fn)zy*y*3 outz.mean() print(z,out)注意 atorch.randn(2,…...
Linux--进程池
1.一个父进程生成五个子进程且分别建立与子进程管道 ①用for循环,结束条件为<5 ②father父进程每次都要离开for循环,生成下一个子进程和管道 2.#include <cassert>和#include <assert.h>的区别 assert.h 是 C 标准库的头文件ÿ…...
SpringCloudAlibaba微服务实战系列(四)Sentinel熔断降级、异常fallback、block细致处理
SpringCloudAlibaba Sentinel降级和熔断 接着上篇文章的内容,在Sentinel中如何进行降级和熔断呢? 熔断降级规则 降级规则 在Sentinel中降级主要有三个策略:RT、异常比例、异常数,也是针对某个资源的设置。而在1.8.0版本后RT改为…...
WebDAV之π-Disk派盘+ WinSCP
WinSCP是一个免费的开源文件传输应用程序,它使用文件传输协议,安全外壳文件传输协议和安全复制协议来进行纯文件或安全文件传输。该应用程序旨在与Windows一起使用,并支持常见的Windows桌面功能,例如拖放文件,跳转列表…...
Python案例分析|使用Python图像处理库Pillow处理图像文件
本案例通过使用Python图像处理库Pillow,帮助大家进一步了解Python的基本概念:模块、对象、方法和函数的使用 使用Python语言解决实际问题时,往往需要使用由第三方开发的开源Python软件库。 本案例使用图像处理库Pillow中的模块、对象来处理…...
音视频——压缩原理
H264视频压缩算法现在无疑是所有视频压缩技术中使用最广泛, 最流行的。随着 x264/openh264以及ffmpeg等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大降低了人们使用H264的成本。 但为了用好H264,我们还是要对…...
微服务 云原生:搭建 K8S 集群
为节约时间和成本,仅供学习使用,直接在两台虚拟机上模拟 K8S 集群搭建 踩坑之旅 系统环境:CentOS-7-x86_64-Minimal-2009 镜像,为方便起见,直接在 root 账户下操作,现实情况最好不要这样做。 基础准备 关…...
C++中的数学问题---进制转换
二进制转十六进制 string binToHex(string bin){string hex"";if(bin.size()%4!0){for(int i0;i<(4-bin.size()%4);i){bin"0"bin;}}for(int i0;i<bin.size();i4){string tmpbin.substr(i,4);bitset<4>b(tmp);hexb.to_ulong()<10?char(b.t…...
开发一个RISC-V上的操作系统(三)—— 串口驱动程序(UART)
目录 文章传送门 一、什么是串口 二、本项目串口的FPGA实现 三、串口驱动程序的编写 四、上板测试 文章传送门 开发一个RISC-V上的操作系统(一)—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统(二&…...
nuxt项目部署,npm run build 和npm run generate的区别
每日鸡汤:每个你想要学习的瞬间都是未来的你向自己求救 非服务端渲染的项目,比如普通的vite vue项目,我们在部署生产环境的时候,只需要两步 运行 npm run build 然后得到了一个 dist 文件夹将这个dist文件夹部署到一个静态服务器…...
数据仓库设计理论
数据仓库设计理论 一、数据仓库基本概念 1.1、数据仓库介绍 数据仓库是一个用于集成、存储和分析大量结构化和非结构化数据的中心化数据存储系统。它旨在支持企业的决策制定和业务分析活动。 1.2、基本特征 主题导向:数据仓库围绕特定的主题或业务领域进行建模…...
数据接口有哪些?(数据接口有哪几种)
数据接口是指不同应用程序或系统之间交换数据的通信界面。在现代信息化社会中,数据接口扮演着极为重要的角色,它们使得不同平台之间能够相互连接和交流,从而实现数据共享和应用集成。 数据接口的种类繁多,常见的有以下几种&#…...
华为云CodeArts产品体验的心得体会及想法
文章目录 前言CodeArts 的产品优势一站式软件开发生产线研发安全Built-In华为多年研发实践能力及规范外溢高质高效敏捷交付 功能特性说明体验感受问题描述完结 前言 华为云作为一家全球领先的云计算服务提供商,致力于为企业和个人用户提供高效、安全、可靠的云服务。…...
下载安装:SQLite+SQLiteStudio+VS
目录 1、SQLite 1.1、下载SQLite 1.2、配置SQLite的环境变量 2、SQLite Studio 2.1、下载SQLite Studio 2.2、安装SQLite Studio 3、Visual Studio 3.1、下载Visual Studio 3.2、安装Visual Studio 1、SQLite 1.1、下载SQLite SQLite官网:SQLite Downl…...
nginx路由
一般我们经常在访问网站时,通常会遇到输入某个页面的网址时,出现路由的转发,重定向等。可能访问的是一个网址,出来的时候就显示的是另外的地址。这是由于使用了nginx的缘故,保护了网址的安全性 (1…...
MobPush Android SDK 厂商推送限制
概述 厂商推送限制 每个厂商通道都有对应的厂商配额和 QPS 限制,当请求超过限制且已配置厂商回执时,MobPush会采取以下措施: 当开发者推送请求超过厂商配额时,MobPush将通过自有通道进行消息下发。当开发者推送请求超过厂商 QP…...
计算机网络 day7 扫描IP脚本 - 路由器 - ping某网址的过程
目录 network 和 NetworkManager关系: 实验:编写一个扫描脚本,知道本局域网里哪些ip在使用,哪些没有使用? 使用的ip对应的mac地址都要显示出来 计算机程序执行的两种不同方式: shell语言编写扫描脚本 …...
gitee 配置ssh 公钥(私钥)
步骤1:添加/生成SSH公钥,码云提供了基于SSH协议的Git服务,在使用SSH协议访问项目仓库之前,需要先配置好账户/项目的SSH公钥。 绑定账户邮箱: git config --global user.name "Your Name" git config --glob…...
JAVA面试总结-Redis篇章(七)——数据淘汰策略
JAVA 面试总结-数据淘汰策略...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
