C语言-第二章:分支和循环语句

分支和循环

前置知识

结构

  • 顺序结构

  • 选择结构

  • 循环结构

语句

  • 定义:C语言中,由一个分号;隔开的就是一条语句

int a =0;
  • 只有一个分号,也是一个语句,叫空语句

分支语句和循环语句

分支语句(选择结构)

举例
  • if

  • switch

if语句
单分支if
#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{

	int age = 20;
	if (age < 18)
		printf("未成年\n");
	return 0;
}

20——什么都不输出
18——输出未成年
if与else
#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{

	int age = 11;
	if (age < 18)
		printf("未成年\n");
	else
		printf("成年\n");
	return 0;
}
if + else if + else
#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{

	int age = 100;
	if (age < 18)
		printf("未成年\n");
	else if (age >= 18 && age < 28)
		printf("青年\n");
	else if (age >= 28 && age < 50)
		printf("壮年\n");
	else if (age >= 50 && age < 90)
		printf("老年\n");
	else
		printf("晚年\n");  //最后这个else可以省略,也可以留着
	return 0;
}
执行多条语句
  • 如果条件成立,要执行多条语句,就应该使用代码块

#include 
int main()
{
    if(表达式)
    {
        语句列表1;
    }
    else
    {
        语句列表2;
    
    }
    return 0;
}
  • 这里的一对{}就是一个代码块

悬空else
  • else和离它最近的未匹配的if进行匹配

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	int a = 0;
	int b = 2;
	if (a == 1)
		if (b == 2)
			printf("hehe\n");
	else
		printf("haha\n");
	return 0;
}

//这个没有输出haha,因为else与第二个if匹配,由于第一个if表达式的条件为假,所以没有进入下面的语句                                  
  • 对上述进行改进,输出haha,这样就是一个好代码

#include 
int main()
{
    int a = 0;
    int b = 2;
    if(a == 1)
    {
        if(b == 2)
            printf("haha\n");
    }
    else 
        printf("haha\n");
    return 0;
}

或者什么都不输出

#include 
int main()
{
    int a = 0;
    int b = 2;
    if(a == 1)
    {
  
        if(b == 2)
            printf("hehe\n");
        else
            printf("haha\n");
    }
   
    return 0;
}
if书写形式对比
  • 代码1,代码可读性不是很强

if (condition){
    return x;
}
return y;

//条件成立就返回x,不成立就返回y
  • 代码2,更加容易读懂

if(condition)
{
    return x;
}
else
{
    return y;
}
  • 代码风格

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

#include 
int main()
{
    int num = 4;
    if (num = 5)
    {
        printf("呵呵\n");
    }
    return 0;
}


//会输出呵呵,因为此处=给num赋值,而不判断相等,要判断相等应用 == 
将if那里改成if(5 == num)更优,将来判断常量与变量相不相等,应该把常量放到等号左边来判断
练习
判断一个数是否为奇数,输出1-100之间的奇数
#define _CRT_SECURE_NO_WARNINGS
#include 
#include

#include 
int main()
{
    int i = 1;
    while (i <= 100)
    {
        if (i % 2 == 1)       //或者  if (i % 2 != 0)
            printf("%d", i);  //%d后面如果加上\n就换行
        i++;
    }
    return 0;
}

也可以这样写

#include 
int main()
{
    int i = 1;
    while (i <= 100)
    {
        printf("%d", i);
        i+=2;
    }
    return 0;
}
//这就是算法,有的时候为了达到一种目的,我们可以有多种算法
switch语句
前提
  • 不太好的例子

#define _CRT_SECURE_NO_WARNINGS
#include 
#include
int main()
{
	int day = 0;
	scanf("%d,&day");
	if (1 == day)
		printf("星期1\n");
	else if (2 == day)
		printf("星期2\n");
	else if (3 == day)
		printf("星期3\n");
	else if (4 == day)
		printf("星期4\n");
	else if (5 == day)
		printf("星期5\n");
	else if (6 == day)
		printf("星期6\n");
	else if (7 == day)
		printf("星期7\n");
		return 0;
}
  • 优化:当需要判断的选项较多时,使用多个 if 语句会使代码看起来冗长,不易维护。一个更好的方法是使用 switch 语句,可以简化代码并提高可读性。此外,可以添加一个默认情况来处理无法匹配的输入。

杂记
  • switch后面有一个括号,放一个整形表达式,这个整形表达式结果是几,它就从case几进去

  • switch判断,case作为一个入口进去,而从哪里出去,是由break决定的,break用来跳出switch语句

  • default:当你想选择的结构都不符合switch语句,后面的情况不再执行,default可有可无,处理非法,可以加上,后面什么都不写

  • 编程好习惯:在每个switch语句中都放入一条default子句是一个好习惯,甚至可以在后面再加一个break

  • 表达式必须是整形常量表达式

定义

switch语句也是一种分支语句,常常用于多分支的情况,case决定入口,break决定出口

结构
switch(整型表达式)
{
        语句项
}
语句项
//是一些case语句
//如下:
case 整形常量表达式,不能是变量,能是1而不能是n
    语句;
优化后的代码
#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	int day = 0;
	scanf("%d", &day);
	switch (day)
	{
	case 1:
		printf("星期1\n");
		break;
	case 2:
		printf("星期2\n");
		break;
	case 3:
		printf("星期3\n");
		break;
	case 4:
		printf("星期4\n");
		break;
	case 5:
		printf("星期5\n");
		break;
	case 6:
		printf("星期6\n");
		break;
	case 7:
		printf("星期7\n");
		break;
	default:
		printf("输入错误\n");
	}
	return 0;
}

循环语句

  • while

  • for

  • do while

while语句(循环)
例子1
  • 死循环打印hehe

#include

int main()
{
	while (1)
		printf("hehe\n");
	return 0;
}
例子2
  • 打印1-10

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	int i = 1;            //初始化
	while (i <= 10)       //判断
	{
		printf("%d ", i);
		i++;          //调整
	}
	return 0;
}
break
  • 在上面printf上面加上

if (i==5)
    break;

当执行到i = 5 时,循环就停止

  • 作用:在循环中只要遇到break,就停止后期所有的循环,直接终止循环,所以while中的break是用于永久终止循环的

continue
  • 如果把break换成continue,按住F10进行调试,就陷入了死循环,卡到4就一直循环,当遇到5时就不往后走了,代码就不执行啦,作用结束本次循环continue后面的部分,回到循环条件处

  • 作用:continue是用于终止本次循环的,也就是本次循环中的continue后边的代码不会执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断

语法结构
  • while表达式 循环语句

getchar函数
  • 函数机制:

  • getchar()函数实际上是int getchar(void),所以它返回的是ASCII码,所以只要是ASCII码表里有的字符它都能读取出来。在调用getchar()函数时,编译器会依次读取用户键入缓存区的一个字符(注意这里只读取一个字符,如果缓存区有多个字符,那么将会读取上一次被读取字符的下一个字符),如果缓存区没有用户键入的字符,那么编译器会等待用户键入并回车后再执行下一步 (注意键入后的回车键也算一个字符,输出时直接换行)。

  • 作用:接受键盘输入的字符,会把字符返回来,。下面把接收的字符放到ch里面,然后用putchar打印出来

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	int ch = getchar();
	putchar(ch);
	printf("%c\n", ch);
	return 0;
}
  • 在while循环中的应用——代码1

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	int ch = 0;
	while ((ch = getchar()) != EOF)
	{
		putchar(ch);
	}
	return 0;
}
//这里输ctrl+z可以停下来,-1也可以,因为是EOF的缘故,其他的不行
//这里输EOF也不会停止,因为系统看成是E,O,F
//ctrl+c是结束进程,ctrl+z是输入文件终止符
//EOF - end of file ->-1,文件结束标志
//只要输一个ctrl+z,getchar就能获取一个EOF,放到ch里面去
  • 关于getchar() \n读取问题

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	/*int ch = 0;
	while ((ch = getchar()) != EOF)
	{

		putchar(ch);
	}*/
	int ret = 0;
	char password[20] = {0};
	printf("请输入密码:>");
	scanf("%s", password); 
        //scanf把123456给拿走了,里面还有一个\n,就让getchar拿走了
	//缓冲区还剩余一个‘\n'
	//读取一下'n'
	getchar();  //加上这个,把\n干掉
	printf("请输入(Y/N):>" );
	ret = getchar();
	if (ret == 'Y')
	{
		printf("确认成功\n");
	}
	else
	{
		printf("放弃确认\n");
	}
	return 0;

}
  • while ((ch = getchar()) != '\n')实际应用价值

#define _CRT_SECURE_NO_WARNINGS
#include 
#include

int main()
{
	/*int ch = 0;
	while ((ch = getchar()) != EOF)
	{

		putchar(ch);
	}*/
	int ret = 0;
	int ch = 0;
	char password[20] = {0};
	printf("请输入密码:>");
	scanf("%s", password);       
        //scanf把123456给拿走了,里面还有一个\n,就让getchar拿走了
	//缓冲区还剩余一个‘\n'
	//读取一下'n'
	while ((ch = getchar()) != '\n')
	{
		;
	}                           如果不加这个,当输入123456 abcd就会错误
	printf("请输入(Y/N):>" );
	ret = getchar();
        //ret变量用于存储用户输入的字符,getchar函数用于从输入缓冲区中读取一个字符。
	if (ret == 'Y')
	{
		printf("确认成功\n");
	}
	else
	{
		printf("放弃确认\n");
	}
	return 0;

}
  • chatgpt对上述代码的分析

scanf("%s", password):使用scanf函数读取用户输入的密码,由于%s会读取空格之前的字符,因此如果用户输入的密码中有空格,那么空格后面的内容将被舍弃。

while ((ch = getchar()) != '\n'):使用getchar函数读取输入缓冲区中的换行符,以避免该字符被下一次输入函数读取。

ret = getchar():使用getchar函数读取用户输入的确认信息。

如果输入123456 abcd,如果没有while ((ch = getchar()) != '\n')这段代码,那么程序会将abcd作为确认信息读取,并将其与Y进行比较,最终输出“放弃确认”。加上该代码段可以避免这种错误。

综上所述,这段代码的功能是接受用户输入的密码和确认信息,如果用户确认密码,则输出“确认成功”,否则输出“放弃确认”。
    
在输入"123456 abcd"时,scanf函数会把"123456"读取到password数组中,但它并不会读取空格或者其他非数字字符。因此,空格字符和"abcd"字符串会留在输入缓冲区中等待下一次输入函数读取。

在调用getchar函数时,它会从输入缓冲区中读取一个字符,包括空格字符和换行符,然后将其作为整数返回。在这个例子中,如果没有while ((ch = getchar()) != '\n')语句,程序会在下一个getchar函数调用时读取缓冲区中的空格字符,导致程序无法正常运行。

因此,为了避免这种情况,我们需要在读取确认信息之前调用一次getchar函数来读取输入缓冲区中的换行符,确保确认信息只包含单个字符,从而可以正常比较。
  • 代码2

#include 
int main()
{
    while ((ch = getchar()) != EOF)
    {
        if (ch < '0' || ch >'9'
            continue;
        putchar(ch);
    }
    return 0;
}

//只打印字符0-字符9,其他内容不打印
for循环
语法
for(表达式1;表达式2,表达式3)
    循环语句;
初始化表达式:在循环开始之前执行一次,用于初始化循环控制变量。这个表达式通常用于给循环控制变量赋初始值,例如:int i = 0;。

条件表达式:在每次循环开始之前,判断循环是否继续执行。如果条件为真,则继续循环;如果条件为假,则跳出循环。例如:i < 10。//条件判断部分

更新表达式:在每次循环结束之后执行,用于更新循环控制变量的值。例如:i++,表示每次循环结束后,i 的值增加 1。           //调整部分
基本形式

打印1-10的数字

#include 
int main()
{
    int i = 0;
    for (i = 1; i <= 10; i++)
    {
        printf("%d ", i);
    }
    return 0;
}
break
#include 
int main()
{
    int i = 0;
    for (i = 1; i <= 10; i++)
    {
        if (i == 5)
            break;
        printf("%d ", i);
    }
    return 0;
}

//输出:1 2 3 4
continue
#include 
int main()
{
    int i = 0;
    for (i = 1; i <= 10; i++)
    {
        if (i == 5)
            continue;
        printf("%d ", i);
    }
    return 0;
}
   
//输出:1234678910

不会死循环,此处与while不同,下面对比一下while循环,while会死循环,主要区别在开头

#include 
int main()
{
    int = 1;
    
    while(i<=10)
    {
        printf("%d ",i);
        i ++;
    }
}
建议
  • 不可在for循环体内修改变量,防止for循环失去控制,比如在for循环内加个i =5

  • 建议for语句的循环控制变量的取值采用"前闭后开区间"写法

在判断处最好写成i<10而非i<=9
for循环变种-变种1
#include 
int main()
{
    for(;;)
    {
        printf("hehe\n");
        
    }
    return 0;
}
  • for循环的初始化,判断,调整都可以省略,如果判断部分被省略,判断条件就是恒为真

  • 如果不是非常熟练,建议不要随便省略

for循环变种-变种2
#include 
int main()
{
    int x,y;
for (x=0,y=0;x<2 && y<5; ++X,y++

{
    printf("hehe\n");
}
小问题

下列循环要多少次

#include 
int main()
{
    int i = 0;
    int k = 0;
    for(i =0,k=0;k=0;i++,k++)
        k++;
    return 0;
}

//上面那个不是判断语句,而是把0赋值给了k,表达式结果是k的值,k的结果是0,0为假,那个地方就是假,意味着循环   压根就不进去
//因此循环0次

关于为假不被执行

在 C 语言中,条件语句(如 if、while、for 等)的判断都是基于条件表达式的值。如果该值为零,则视为假,否则视为真。

这是因为在 C 语言中,零值被视为“假”,非零值被视为“真”,这种约定俗成的规定被称为“真值测试”。

例如,在条件语句中,如果条件表达式的值为零,则被视为假,执行 else 分支(如果有的话)或跳过整个语句块;如果条件表达式的值为非零值,则被视为真,执行 if 分支(如果有的话)。

在这个问题中,条件表达式 k = 0 的值为 0,因此被视为假,循环体内的语句不会被执行。而如果条件表达式的值为非零值,就会被视为真,循环体内的语句就会被执行。
do..while()循环
语法
do 
    循环语句;
while(表达式);
chatgpt版:
do {
    循环体语句;
} while (循环条件);
举例
#include 

int main()
{
    int i = 1;
    do
    {
        printf("%d", i);
        i++;
    }
    while (i < 10);

    return 0;
}
特点
  • 循环至少执行一次,使用场景有限,不经常使用

练习
计算n的阶乘
#include 

int main() {
    int i = 0;
    int n = 0;
    int ret = 1;
    scanf("%d",&n);
    for (i = 1; i <= n; i++)
    {
        ret = ret * i;
    }
    printf("ret = %d\n", ret);
    return 0;
}
计算1!+2!+3!+...+10!
#include 

int main() {
    int i = 0;
    int n = 0;
    int ret = 1;
    int sum = 0;
    for (n = 1; n <=3;n++)
    {
        ret = ret * n;    //提高效率
        //n的阶乘
        sum = sum + ret;
    }
    
    printf("sum=%d\n", sum);
    return 0; 
}
在一个有序数组中查找具体的某个数字n,编写int binsearch(int x,intv[],int n);功能:在v[0]<=v[1]<=v[2]<=...<=v[n-1]的数组中查找x
#include 

int main() {
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int k = 7;
    //写一个代码,在arr数组中(有序的)找到7
    int i = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    for (i < 0; i < sz; i++)
    {
        if (k == arr[i])
        {
            printf("找到了,下标是:%d\n", i);
            break;
        }
    }
    if (i == sz)
        printf("找不到\n ");
        return 0;
}
//输出:找到了
//如果7那里改为17,就找不到
二分查找算法(折半)
#include 

int main()
{
    int k = 7;
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int sz = sizeof(arr) / sizeof(arr[0]); //计算元素个数
    int left = 0;  //左下标
    int right = sz - 1;  //右下标
    while (left<=right)
    {
        int mid = (left + right) / 2; //根据下面随时调整
        if (arr[mid] > k)
        {
            right = mid - 1;
        }
        else if (arr[mid] < k)
        {
            left = mid + 1;
        }
        else
        {
            printf("找到了,下标是:%d\n", mid);
            break;
        }
    }
    if (left > right)
    {
        printf("找不到\n");
    }
    return 0;
}
  • 上面int mid = (left + right) / 2;这行代码为什么不能写到while外面

可以将 int mid = (left + right) / 2; 这行代码写到 while 循环的外面,但这样做可能会导致程序的一些问题。因为在循环外面定义的变量 mid 的值只会在循环开始时计算一次,而在循环执行过程中,变量 left 和 right 的值可能会被修改,导致 mid 的值不再是数组中间的位置。这会导致程序无法正确地进行二分查找。

因此,将 int mid = (left + right) / 2; 这行代码放在 while 循环中,可以确保在每次循环开始时都重新计算数组的中间位置,以确保程序能够正确地进行二分查找。
编写代码,演示多个字符从两端移动,向中间汇聚
#define _CRT_SECURE_NO_WARNINGS
#include 
#include  //引strlen等字符串函数
#include //引sleep
#include 
#include //引system
#include 
int main()
{
    char arr1[] = "welcome to bit!!!!!!";  //数组元素个数不给定,用后面字符串去初始化它,字符串要求多少,数组就会开辟多少
    char arr2[] = "####################";  //把#换成空格食用效果更佳
    int left = 0;
    //int right = sizeof(arr1) / sizeof(arr1[0] - 2); //上一个是数组,没有/0,这是个字符串,有,所以减2
    int right = strlen(arr1)-1;  //下标总是比元素个数少1,strlen遇到/0就停止,所以只需要-1

    while (left <= right)
    {
        arr2[left] = arr1[left];
        arr2[right] = arr1[right];
        printf("%s\n", arr2);

        //休息一秒
        Sleep(1000); //
        //执行系统命令的一个函数 - cls清空屏幕
        system("cls");  //
        left++;
        right--;
   }
    printf("%s\n", arr2);

    return 0;
}

//好玩捏
编写代码事项,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输如错误,则退出程序)
  • 注意 == 不能用来比较字符串是否相等,应该用strcmp函数

#define _CRT_SECURE_NO_WARNINGS
#include 
#include  //引strlen等字符串函数
#include //引sleep
#include 
#include //引system
#include 
int main()
{
    int i = 0;
    char password[20] = { 0 };
    for (i = 0; i < 3; i++)
    {
        printf("请输入密码:>");
        scanf("%s", password);  //可以直接将数组名传递给scanf函数,而不需要取地址操作
        if (strcmp(password , "123456") ==0 )  
    // ==不能用来比较两个字符串是否相等,应该使用一个库函数-strcmp,若前大于后,返回大于0的值
        {
            printf("登录成功\n");
            break;
        }
        else
        {
            printf("密码错误\n");
            //下面更人性化一点
            Sleep(500);  //
            system("cls");//
        }
       
    }
    if (i == 3)
        printf("三次密码均错误,退出程序\n");
}

你可能感兴趣的:(C语言,c#,网络安全,c语言)