C语言初阶--1.分支与循环语句

前言:

学习笔记,参考各路大佬所记录,若有侵犯,请告知删改(我要30天学完!)
参考:二十万字带你入门C语言-史上最强C语言教程(汇总篇)-优快云博客
C 语言教程 | 菜鸟教程
C语言程序设计从入门到进阶【比特鹏哥c语言2024完整版视频教程】(c语言基础入门c语言软件安装C语言指针c语言考研C语言专升本C语言期末计算机二级C语言c语言_哔哩哔哩_bilibili

刷题:编程语言初学训练营_在线编程+题解_牛客题霸_牛客网 

上一节内容:初识C语言(基于Visual Studio 2022)-优快云博客

 1.什么是语句(--------Day4---------)

C语言中, 一般一个分号就是一条语句 ,语句可分为以下五类:
1. 表达式语句
2. 函数调用语句
3. 控制语句(分支与循环语句归属于此)
4. 复合语句
5. 空语句
控制语句 用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成, C 语 言有九种控制语句。
可分成以下三类:
1. 条件判断语句也叫分支语句:if语句、switch语句;
2. 循环执行语句:do while语句、while语句、for语句;
3. 转向语句:break语句、goto语句、continue语句、return语句。

C语言是
结构化的程序设计语言,包括 顺序结构、选择结构、循环结构。

2.分支语句(选择结构-只选择一个

人生处处充满了选择,每一个选择都是一次道路上的分支,既有但分支又有多分支错综复杂,路在脚下任你踏足,而你为什么这么选,是基于什么条件选择的,选择后又会产生什么样的结果,都是值得我们深思的。

2.1 if语句

语句结构1

if (条件判断表达式语句1)
{
        语句1;        //如果表达式为真,则执行语句1,否则跳过语句1不执行

        语句...            //若只执行单挑语句可以省略{}大括号(else也一样)
}                                

条件判断表达式语句使用 

语句结构2
if (条件判断表达式语句1)
{
        语句1;           //如果表达式为真,则执行语句1,否则跳过语句1不执行

        ...
}
else                        // 也就是不满足上述条件,执行语句2
{
        语句2;

        ...                       ////若只执行单挑语句可以省略{}大括号(else也一样)
}

语句结构3
if (条件判断表达式语句1)           //如果表达式1为真,则执行语句1, 并且不再判断后续的else //(if)语句, 否则跳过语句1不执行 ,判断下一个else if语句                           
{                                                 
        语句1;   

        ...     
}
else  if (条件判断表达式语句2)      //如果表达式2为真,则执行语句2, 并且不再判断后续的//else (if)语句, 否则跳过语句2不执行 ,判断下一个else if语句 

{
        语句2;

        ...

}

......                //可以接多个else if

else                //若前面的表达式语句都为假0,则执行语句n

{   

        语句n;

        ...

}


所有的if结构中若执行语句只有一条,可以省略{}大括号,if else的分支语句只会选择一条执行语句执行,多个if else 嵌套串联时,else会选择前面最近的一个if,而不是看格式对齐,养成良好的{}代码习惯

练习

1. 判断一个数是否为奇数
如何判断一个数是否是奇数呢?对2取模运算
#include <stdio.h>
int main(void)
{
        int a = 0;                         //定义输入变量a为整型并且初始化
        scanf("%d", &a);             //键盘输入函数
        if(a % 2 == 1)                 //整型a对2取模 (得到余数),== 关系操作符,非0 即1判断是否等于1 
        {
                printf("%d是奇数。\n",  a);
        }
        else
        {
                printf("%d是偶数。\n",  a);
        }
        return 0 ;
}
2. 输出1-100之间的奇数
添加一个循环条件即可

2.2 switch语句

switch语句常常用于多分支的情况,允许嵌套使用
格式:
switch ( 整型表达式 )
{
       
        case 整形常量表达式1 ://字符由ASCII码编译的整型关系运算符结果是非0即1的整型
          语句1 ; 
       case 整形常量表达式2 :
          语句2 ;
        ...
        default:
           语句n;break;
}
说明 :整型表达式的数值与整形常量表达式数值进行对比,若相等,则执行相等项语句及其后所有语句,否则跳出语句。多语句也可不使用{}大括号

break关键字

        在switch语句中,我们没办法直接实现分支,搭配break使用才能实现真正的分支。break语句 的实际效果是把语句列表划分为不同的分支部分,若满足则直接跳出switch而不接着执行后续语句。

default子句

如果表达的值与所有的case 标签的值都不匹配怎么办?
其实也没什么,结构就是所有的语句都被跳过而已。 程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default 子句,把下面的标签
default :写在任何一个 case 标签可以出现的位置。 当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行。
所以,每个 switch语句中只能出现一条default 子句。 但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case 标签一样执行default子句。
编程好习惯 : 在每个 switch 语句中都放一条 default 子句是个好习惯,甚至可以在后边再加一个 break

练习

1. 输入 1-5 ,输出的是 “weekday”; 输入 6-7 ,输出 “weekend”

2.判断输出结果 

答案:5 3(注意break只跳出当前一级的选择或者循环,而不是所有)

3.循环语句

3.1 While语句(--------Day5---------)

3.1.1 语法

首先记住While 最基本的使用方式

while ( 表达式语句 )         // 表达式语句非0即1
{
         循环语句 ;              //满足条件就执行
}

3.1.2 While语句中的“跳出”(continue和break)

continue 在while循环中的作用:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,
而是直接跳转到while语句的判断部分。进行下一次循环的条件判断。
break 在while循环中的作用:
只要遇到break,就停止后期的所有的循环,直接终止循环, while中的break是用于永久终止循环。

通过代码理解【本次】和【所有】的区别


运行结果:

3.1.3 练习

(1)输出什么

 2 3 4 6 7 8 9 10 11
注意 i ++;位置对代码的影响

(2)ASCII码_牛客题霸_牛客网

如何打印字符呢??? %c即可

while循环数数??? 不可能的,利用sizeof关键字计算数组长度

(3)出生日期输入输出_牛客题霸_牛客网

依旧是考printf输出格式和sanf输入格式

 

(4)学生基本信息输入输出_牛客题霸_牛客网 
%.2f是直接删除超过两位的小数,如何四舍五入呢???

 (5)printf的返回值_牛客题霸_牛客网

3.2 for循环(--------Day6---------)

3.2.1 语法

for ( 表达式 1 ; 表达式 2 ; 表达式 3 )
{
        循环语句;
}
表达式 1
表达式 1 初始化部分 ,用于初始化循环变量的。(只执行一次)
表达式 2
表达式 2 条件判断部分 ,用于判断循环时候终止。
表达式 3
表达式 3 调整部分 ,用于循环条件的调整。
其执行逻辑是:先初始化表达式1 (只执行一次) ,判断表达式2,若成立则运行循环语句并执行表达式3,再次进行判断,重复操作,直到不满足,跳出循环。
打印0-10
和while循环语句对比,for循环更为简洁,且for虚幻将初始化i、表达式语句、i值变化 三个必须条件集成在一个()中,而while则需分开,偶尔还容易出现i++ ;的位置影响代码运行问题。

3.2.2 for循环的“跳出”

与while语句中的一致(但略有区别)

这里初始化i = 1,与while中不一样是因为for循环时先执行后++,而之前while代码将i++;写在了执行语句的前面,会先加一次,是先++后执行。 因为while循环中的contiue是跳到下一次while中,但是while中没有调整i的数值,而for循环也是跳到这一次for循环中的i++部分再进行下一次判断

3.2.3 for循环的变种

(1)可省略条件

全部省略进入死循环

(2)嵌套

可以尝试做一个9*9乘法口诀表

(3)多个变量

(4)只省略初始化部分


只打印了10个为啥不是10*10个呢???

i = 0 时,内层循环开始执行,j0递增到9,打印10次“hehe”,内层循环结束后,j的值为10,i变动时,内层条件不再满足。

3.2.4 练习

1. 请问循环要循环多少次?

#include <stdio.h>
int main ()
{
        int i = 0 ;
        int k = 0 ;
        for ( i = 0 , k = 0 ; k = 0 ; i ++ , k ++ )
       
                k ++ ;
        return 0 ;
}

答:0次,因为k=0虽然是赋值语句,但是它的结果是0,判断为假,不执行。

3.3 do...while()循环

3.3.1 语法

do
{
        循环语句;
}
while(表达式);
执行逻辑:先do循环语句后判断(易错)

循环至少执行一次的特性 

3.3.2 do while循环中的“跳”(breakcontinue

和上面两个循环一样

3.4 练习

1. 计算 n 的阶乘

2. 计算 1!+2!+3!+……+10!
此题还有其它秒解
3. 在一个有序数组中查找具体的某个数字 n (讲解二分查找)
原理:
计算mid的归一化处理(可防溢出,下图未使用)
4. 编写代码,演示多个字符从两端移动,向中间汇聚。
单行显示,并且有动画效果
5. 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则 提示登录成,如果三次均输入错误,则退出程序

4. goto语句

4.1 介绍

        C语言中提供了可以随意滥用的 goto语句和标记跳转的标号,goto 语句是一种无条件跳转指令,可以让程序控制流直接跳转到函数内的指定标签位置。虽然  goto 语句在某些场景下非常有用,但过度使用会导致代码结构混乱(即所谓的 "spaghetti code"),因此需要谨慎使用。

语法:

goto label;  // 跳转到标签位置
...
label:       // 标签声明(标识符后加冒号)
{    
    statement;   // 标签后的语句
}

  • 标签:是一个标识符(遵循变量命名规则),后跟一个冒号 :,必须与 goto 位于同一函数内。
  • 执行流程:当执行到 goto label; 时,程序会立即跳转到 label: 处继续执行。
(1) 跳出多层嵌套循环

当需要从深层嵌套的循环中立即退出时,goto 比多个 break 语句更简洁:

for (...) {
    for (...) {
        if (condition)
            goto exit_loop;  // 直接跳出两层循环
    }
}
exit_loop:
// 继续执行后续代码
(2) 错误处理

在函数中统一处理错误情况,避免重复代码:

int func() {
    // 分配资源
    int* ptr = malloc(sizeof(int));
    if (!ptr)
        goto error;
        
    // 执行操作...
    if (error_condition1)
        goto error;
        
    // 更多操作...
    if (error_condition2)
        goto error;
        
    // 成功返回
    return 0;
    
error:
    // 统一释放资源
    free(ptr);
    return -1;
}
(3) 实现状态机

在简单状态机中控制状态转换:

int state = 0;
start:
switch (state) {
    case 0:
        // 状态0处理
        state = 1;
        goto start;
    case 1:
        // 状态1处理
        state = 2;
        goto start;
    case 2:
        // 状态2处理
        break;
}

4.2 禁用场景

  • 跨函数跳转goto 不能跳转到其他函数内的标签。
  • 破坏结构化编程:避免在复杂代码中随意使用 goto,例如:
    // 糟糕的示例:代码逻辑混乱
    goto step2;
    step1: printf("Step 1\n");
    goto step3;
    step2: printf("Step 2\n");
    goto step1;
    step3: printf("Step 3\n");
    
  • 跳过变量初始化goto 不能跳过变量初始化语句,否则会导致编译错误:
    goto skip;
    int x = 10;  // 不能跳过初始化

4.3 案例

关机程序

若打不了中文不知道,开cmd可以,可以尝试进行如下操作

补充


getchar()与putchar()

getchar() 和 putchar() 是 C 语言标准库中用于字符输入输出的函数,属于 stdio.h 头文件。
getchar() 用于从标准输入(通常是键盘)读取单个字符,返回类型为 int(以处理 EOF 标志)。

putchar() 用于向标准输出(通常是屏幕)写入单个字符,参数类型为 int,但实际只处理低 8 位(即一个字符)

与 scanf() 和 printf() 的区别

(1)输入输出单位
  • scanf() 和 printf() 支持格式化输入输出,可以处理多种数据类型(如 %d%f%s)。
  • getchar() 和 putchar() 仅处理单个字符,效率更高,适合简单字符操作。
(2)缓冲区的处理方式
  • scanf() 会跳过空白字符(如空格、换行),直到读取到有效数据,可能残留换行符在缓冲区。
  • getchar() 直接读取输入缓冲区的下一个字符(包括换行符 \n),不会跳过任何字符
    所以有:
    while ((c = getchar()) != '\n' && c != EOF);  // 清空缓冲区
     
    
(3)返回值
  • scanf() 返回成功匹配的参数个数,失败返回 EOF
  • getchar() 直接返回读取的字符(ASCII 值),失败或遇到文件结束返回 EOF
  • printf() 返回输出的字符数。
  • putchar() 返回写入的字符,失败返回 EOF

  (4)对比

  • getchar() 比 scanf("%c") 更高效,因为后者需要解析格式字符串。
  • putchar() 比 printf("%c") 更直接,减少格式化开销。

输入缓冲区

输入缓冲区是计算机系统中用于临时存储输入数据的内存区域,通常在程序读取输入前暂存数据。其作用包括协调输入设备与处理速度的差异、减少频繁I/O操作的开销等。常见于键盘输入、文件读取、网络通信等场景。

输入缓冲区的工作原理

  • 数据暂存:输入设备(如键盘)将数据先写入缓冲区,程序按需从缓冲区读取,避免直接访问硬件导致的延迟。
  • 行缓冲与全缓冲
    • 行缓冲:遇到换行符或缓冲区满时触发读取(如终端输入)。
    • 全缓冲:缓冲区填满后才触发读取(如文件操作)。

清除输入缓冲区的方法

在C中,输入函数(如scanf)可能遗留换行符或无效数据,需手动清除缓冲区:

#include <stdio.h>
void clear_input_buffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF); // 逐字符读取直至换行或文件末尾
}
 

sizeof关键字与strlen()函数

总结:

sizeof是关键字,计算单位是字节,会计算字符串所有长度(包括'\0'),一般习惯/sizeof(数组(0))将单位化为1用于计算数组长度,不过字符char占一个字节可不除。
strlen()是函数,只计算到'\0'(不包含)的长度,单位为1,若没有则直到找到为止,所以arr4和arr6输出为随机值

strcmp函数 

字符串比较大小函数,它会按照字典序对两个字符串进行比较,区分大小写。

  • 函数原型int strcmp(const char *s1, const char *s2);
  • 返回值
    • 若返回值小于 0,表示s1小于s2
    • 若返回值等于 0,表示s1等于s2
    • 若返回值大于 0,表示s1大于s2

数组传参

数组传参实际上传入的是数组的首地址,即是地址则为指针变量

system函数

system 函数是标准库提供的一个用于执行操作系统命令的接口。它允许程序在运行时调用外部命令,实现与操作系统的交互,system 函数的核心作用是在程序中执行操作系统的 shell 命令也就是运行cmd.exe。

函数原型与头文件

#include <stdlib.h>

int system(const char *command);
  • 参数
    • command:指向包含系统命令的字符串指针(如 "shutdown -s -t 60")。
    • 若为 NULL,则检查系统命令处理器是否存在。
  • 返回值
    • 成功:返回命令执行后的退出状态码(由操作系统决定)。
    • 失败:返回 -1(例如命令处理器无法启动)。
    • 特殊情况:若 command 为 NULL 且系统支持命令处理器,则返回非零值。


Windows关机

shoutdown是 Windows 系统中用于关机、重启、注销等操作的命令,通过添加不同的参数,可精确地指定执行的操作和时间。WIN + R 键输入cmd控制,以下是其常见参数及用法介绍:

 
  • /s:用于关闭计算机。例如shutdown /s,会弹出自动关机对话框,默认 30 秒后关机;若使用shutdown /s /t 0,则会立即关闭本地计算机。
  • /r:用于重启计算机。如shutdown /r /t 0,表示立即重启计算机。
  • /a:用于取消正在进行的关机或重启操作。但需注意,取消命令必须在倒计时内执行,对于立即关机(/t 0)无法取消。
  • /f:强制关闭正在运行的程序。当系统中有未保存的工作或未响应的程序时,默认shutdown会等待程序响应,使用此参数可强制终止所有程序,如shutdown /s /f /t 0
  • /m \\计算机名:指定远程计算机进行关机或重启操作。例如,shutdown /s /m \\192.168.1.100 /t 0表示远程关闭 IP 地址为 192.168.1.100 的计算机。
  • /t xxx:设置关机或重启前的倒计时时间,单位为秒。例如,shutdown /s /t 60表示 60 秒后自动关机。
  • /c "说明文字":添加关闭原因,最大支持 512 个字符。例如,shutdown /s /m \\192.168.1.100 /t 30 /c "系统维护,稍后重启",会在远程关机时向目标计算机用户显示此说明。
  • /l:注销当前用户。此参数不能与/m/d参数一起使用。
  • /g:关闭计算机,然后重新启动,并确保所有注册的应用程序都重新启动。
  • /p:在不等待超时或警告的情况下关闭本地计算机,常与/d/f flags 一起使用。
  • /h:使计算机进入休眠状态,可与/f参数一起使用。
  • /hybrid:关闭计算机并为快速启动做准备,必须与/s参数一起使用。
  • /e:用于查看计算机意外关闭的原因。
  • /o:将计算机引导至高级启动菜单选项并重新启动。

eg:shutdown -s -t 60 该命令用于设置计算机在 60 秒后自动关机。其中,-s参数表示关闭本地计算机,-t参数用于设置关机倒计时,单位为秒,这里指定为 60 秒。

shutdown -a 这个命令的作用是取消当前已经设置好的关机操作。如果你之前使用shutdown -s -t等命令设置了定时关机,但后来又想取消该关机计划,那么只需在命令提示符或运行窗口中输入shutdown -a并回车,就可以取消正在等待执行的关机任务,让计算机恢复正常运行状态,不会再按照之前设置的时间关机。

练习(上一节)

第一题                                                                                                                 C

第二题           static有无的区别                                                                 8,10,12,14,16

第三题                                                           B,  A应当为1字节,与类型无关                                   

第四题KiKi学程序设计基础_牛客题霸_牛客网

转义字符

 第五题小乐乐找最大数_牛客题霸_牛客网

第六题计算球体的体积_牛客题霸_牛客网

若float不行改成double,精度更高,例外0.0默认为double类型,0.0f则为float

初始化时,最好赋值,否者容易随意赋值,int a = 0; float b = 0.0f; double c = 0.0;

第七题计算体重指数_牛客题霸_牛客网

注意整数除以整数还是整数,整数除以整数.0即是浮点数运算,加上.0他好你也好

大作业:猜数字游戏

知识预知

(1)时间戳获取
time 函数:获取当前系统时间(从1970 年 1 月 1 日 00:00:00 UTC到现在的秒数),也称为时间戳(Unix Timestamp)

  • 原型
#include <time.h>

time_t time(time_t *timer);
  • 参数
    • timer:指向time_t类型的指针,用于存储时间值。若为NULL,则直接返回时间值。
  • 返回值
    • 成功:返回当前时间戳(time_t类型,通常是long int)。
    • 失败:返回(time_t)-1(极少发生)。
time_t current_time;
current_time = time(NULL);  // 直接获取时间戳
// 或
time(&current_time);        // 通过指针存储时间戳

printf("当前时间戳: %ld\n", (long)current_time);

(2)获取随机值

srand 函数:初始化随机数种子

srand()设置随机数生成器的种子值(seed)。若不调用srand,默认种子为1,导致每次运行程序时rand()生成相同的随机序列。只调用一次。

  • 原型
#include <stdlib.h>
void srand(unsigned int seed);
  • 参数
    • seed:无符号整数,作为随机数生成的起始值。

rand 函数:生成伪随机数

功能

生成伪随机整数,范围为0RAND_MAX(标准库定义的常量,至少为32767)。

原型
#include <stdlib.h>
int rand(void);
  • 返回值
    • 生成的伪随机整数(int类型)。
示例
// 生成0-99之间的随机整数
int random_num = rand() % 100;

// 生成100-200之间的随机整数
int min = 100, max = 200;
int random_range = min + (rand() % (max - min + 1));

// 生成0.0-1.0之间的随机浮点数
double random_float = (double)rand() / RAND_MAX;

三者协作流程

  1. 获取时间戳time(NULL)
  2. 设置随机种子srand(time(NULL))
  3. 生成随机数rand()
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    // 初始化随机种子
    srand((unsigned int)time(NULL));
    
    // 生成10个随机数
    for (int i = 0; i < 10; i++) {
        printf("随机数 %d: %d\n", i+1, rand() % 100);
    }
    
    return 0;
}

猜数字游戏实例

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

// 打印游戏菜单
void menu()
{
	printf("**********************************\n");
	printf("*********** 1.play     **********\n");
	printf("*********** 0.exit     **********\n");
	printf("**********************************\n");
}

// 猜数字游戏的核心逻辑
// RAND_MAX是标准库定义的常量,表示rand函数能返回的最大随机数
void game()
{
	// 生成1-100之间的随机整数
	int random_num = rand() % 100 + 1;
	int input = 0;
	
	printf("游戏开始,请猜一个1-100之间的数字!\n");
	
	while (1)
	{
		printf("请输入猜的数字>:");
		scanf("%d", &input);
		
		if (input > random_num)
		{
			printf("猜大了,再小一点!\n");
		}
		else if (input < random_num)
		{
			printf("猜小了,再大一点!\n");
		}
		else
		{
			printf("恭喜你,猜对了!正确答案就是%d\n", random_num);
			break;  // 猜对后跳出循环结束游戏
		}
	}
}

int main()
{
	int input = 0;
	
	// 用当前时间作为随机数种子
	// 确保每次运行程序时生成不同的随机序列
	srand((unsigned)time(NULL));
	
	// 主循环:使用do-while确保至少执行一次菜单选择
	do
	{
		menu();  // 显示菜单
		printf("请选择>:");
		scanf("%d", &input);
		
		switch (input)
		{
		case 1:
			game();  // 开始游戏
			break;
			
		case 0:
			printf("游戏已退出,欢迎下次再来!\n");
			break;
			
		default:
			printf("选择错误,请输入1或0!\n");
			break;
		}
		
	} while (input);  // 当用户输入0时退出循环
	
	return 0;
}

结语

        代码规范是自己的习惯养成的,多写多敲,多看多想,多读多学

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值