【C语言入门必看】分支语句和循环语句

在这里插入图片描述

前言

本章学习分支语句和循环语句
C语言是结构化的程序设计语言
结构有以下三种:顺序、选择、循环
在这里插入图片描述
语句:C语言中由一个分号;隔开的为一个语句 如 int i = 0;

一、分支语句(选择结构)

2.if语句

语法结构:

if(表达式)
	语句;

表达式结果为真,则执行语句;为假,不执行

C语言中0为假,非0值为真

如:

int main()
{
    
    
	int age = 0;
	scanf("%d", &age);
	if (age < 18)
	{
    
    
		printf("未成年");
	}
	return 0;
}

if(表达式)
	语句1;
else(表达式)
	语句2

如:

int main()
{
    
    
	int age = 0;
	scanf("%d", &age);
	if (age < 18)
	{
    
    
		printf("未成年");
	}
	else
	{
    
    
		printf("成年");
	}
	return 0;
}

③(多分支)

if(表达式1)
	语句1;
else if(表达式2)
	语句2;
:
:
else
	语句n;

如:

int main()
{
    
    
	int age = 0;
	scanf("%d", &age);
	if (age < 18)
	{
    
    
		printf("少年");
	}
	else if(18<=age&&age<30)
	{
    
    
		printf("青年");
	}
	else if(30<=age&&age<50)
	{
    
    
		printf("中年");
	}
	else if (50 <= age && age < 80)
	{
    
    
		printf("老年");
	}
	else
	{
    
    
		printf("老不死");
	}
	return 0;
}
  • 注意事项
    -①if条件判断的错误写法1
int age=10;
  	if(18<=age<30)
  		printf("中年");

其判断逻辑为:先判断18<=age,即18<=10为假,结果为0
再判断0<30为真,结果为1,则显示中年,而10岁明显不是中年,则错误
正确写法:if(18<=age&&age<30)
"&&“为逻辑操作符,意为"且”,同时满足才为真.
②if条件判断的错误写法2

int  a= 1;
	if (a = 2)//本意为判断a和2是都相等,实际将2赋值给a,条件为真,执行
	{
    
    
		printf("hehe");
	}
	return 0;

=:赋值操作符
==:关系操作符,测试"相等"
上述例子应改为if(a==2)
小技巧:写成if(2==a),这样若少写一个=,即if(2=a),则编译器会报错(变量不可赋值给常量)
③执行多条语句应用代码块{}括起来
if语句只能控制后面一条语句,若想控制多条语句,则用{}

int age = 10;
	if (age > 18)
		printf("成年");//10>18为假,不执行
		printf("可以谈恋爱");//执行该条语句,证明该语句不受if控制
		return 0;
		显示:可以谈恋爱

④悬空else

	int a = 0;
    int b = 2;
    if(a == 1)
        if(b == 2)
            printf("hehe\n");
    else//else看上去似和第一个if匹配,实际不是
        printf("haha\n");
    return 0;
    //不显示任何结果

else匹配原则:与距离最近的未匹配的if进行匹配
规范写法:

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

练习:

  1. 判断一个数是否为奇数
  2. 输出1-100之间的奇数
  1. 判断一个数是否为奇数
int main()
{
    
    
	int n = 0;
	scanf("%d", &n);

	if (0 == n % 2)
	{
    
    
		printf("不是奇数");

	}
	else
	{
    
    
		printf("是奇数");
	}
	return 0;
}
  1. 输出1-100之间的奇数
int main()
{
    
    
	int i = 1;
	while (i <= 100)
	{
    
    
		if (1 == i % 2)
		{
    
    
			printf("%d ", i);
		}
		i++;
	}
	return 0;
}
//int i = 1; printf("%d ",i+=2);

2.siwtch语句

switch语句也是分支语句,常用于多分支的情况.比if…else if…else更优\更简便
语法结构:

	switch (整型表达式)
	{
    
    
	case 整型常量表达式:
			语句;
	}

switch常与break搭配使用,达到分支效果
如:

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

说明:case为入口,break为出口.若无break,则会一直往下运行.
default:若case整型常量表达式均不满足,则执行default中的语句.default位置可在任意case语句的位置(习惯放在最后)

是否添加break由我们所想达到的效果决定.
上述例子,若我们想在输入1,2,3,4,5后,显示"工作日";输入6,7,显示"休息日".
则代码为:

int main()
    {
    
    
        int day = 0;
        scanf("%d", &day);

        switch (day)
        {
    
    
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
            printf("工作日\n");
            break;
        case 6:
        case 7:
            printf("休息日\n");
            break;
        default:
        	printf("输入错误");
        }
    }

建议不要漏break和default,养成良好的编程习惯

  • switch可嵌套使用
include <stdio.h>
int main()
{
    
    
    int n = 1;
    int m = 2;
    switch (n)
   {
    
    
    case 1:
            m++;
    case 2:
            n++;
    case 3:
             switch (n)
           {
    
    //switch允许嵌套使用
             case 1:
                    n++;
             case 2:
                    m++;
                    n++;
                    break;
           }
    case 4:
            m++;
             break;
    default:
             break;
   }
    printf("m = %d, n = %d\n", m, n);
    return 0;
}
//m=5,n=3

break只跳出一层所在的switch语句

二、循环语句

1.while语句

语法结构:

	while (表达式)
	{
    
    
		语句;
	}

先来看下if和while的关系:

if (1)
	{
    
    
		printf("hello");
	}
	return 0;
//显示 hello

而将if改为while后:

while (1)
	{
    
    
		printf("hello");
	}
	return 0;
//显示死循环的hello

区别: 若判断条件为真,if语句只执行一次语句,而while语句会一直执行

  • break在while语句中的作用
    如:
int main()
{
    
    
  int i  = 1;
    while(i<=10)
    {
    
    
        if (5==i)//当i==5时,break跳出后面所有的循环
            break; //break:永久终止循环
      printf("%d ",i);
        i++;
    }
    return 0;
}
//显示结果:1 2 3 4 

总结: 循环中遇到break,则终止后面所有的循环,直接结束循环.
while中的break作用是永久终止循环

  • continue在while语句中的作用
    如:
int main()
{
    
    
    int i  = 1;
    while(i<=10)
    {
    
    
        if (5==i)
            continue; //continue跳过本次循环,不会执行后面的代码,而是回到while的判断部分
      printf("%d ",i);//continue跳过本次循环,i++没有执行(i没有调整),进入死循环状态
        i++;
    }
    return 0;
}
//显示结果:1 2 3 4 死(空)循环

总结:continue终止本次循环,即continue后面的代码不会执行,直接跳到while的判断部分,进行下一次循环的入口判断.

1.1getchar()函数

getchar()函数:
①从缓冲区读取一个字符,返回类型为整型(字符型char本质是ASCII值,为整型)
②使用要包含头文件stdio.h
③getchar()函数不仅可以从输入设备获得一个可显示的字符,而且可以获得屏幕上无法显示的字符,如控制字符回车换行,空格等.
注意:1.因为getchar返回类型为整型,所以创建存放字符的变量的类型为整型,如int ch;
2.gechar()读取失败会返回EOF(end of file:文件结束标志),值为-1(整型)
直接上代码:

int main()
{
    
    
  int ch = 0;
    char password[20] = {
    
    0};
    printf("请输入密码>:");
    scanf("%s",password); //数组名本身就是地址,所以不需要再取地址
    printf("确认密码(Y/N)>:");
    ch = getchar();
    if(ch == 'Y')
    {
    
    
      printf("确认成功\n");
    }
    else
    {
    
    
      printf("确认失败\n");
    }
    return 0;
}

运行程序:在键盘输入密码123456,并敲下回车键,结果为确认失败.
分析

程序分析:
①scanf函数读取123456,并不会读取\n,后存到password数组.
②因为缓冲区余下\n,所以getchar函数会直接读取\n,存到ch变量,不会等待键盘输入.
③\n==‘Y’,为假,则"确认失败".
解决方法:缓冲区余下\n,导致不暂停(等待输入),则用getchar();清理缓冲区.

int main()
{
    
    
  int ch = 0;
    char password[20] = {
    
    0};
    printf("请输入密码>:");
    scanf("%s",password); //数组名本身就是地址,所以不需要再取地址
    getchar();//清理缓冲区
    printf("确认密码(Y/N)>:");
    ch = getchar();
    if(ch == 'Y')
    {
    
    
      printf("确认成功\n");
    }
    else
    {
    
    
      printf("确认失败\n");
    }
    return 0;
}

次方法不可取,应用范围有限:
当输入为:12345 abc(中间有空格),仍为"确认失败".
程序分析:
①缓冲区为12345 abc\n.
scanf函数遇到空格会停止.(不读取空格)
③getchar函数读取空格后,缓冲区还剩下abc\n.
④下一个getchar函数读取a,a=='Y’为假,则"确认失败".

优化方法:上述方法只用了一次getchar,无法保证读取的字符一定是\n.优化思路:用循环和空语句取走scanf读取字符后留在缓冲区的字符.

int main()
{
    
    
  int ch = 0;
    char password[20] = {
    
    0};
    printf("请输入密码>:");
    scanf("%s",password);
   
    //清理缓冲区
    while((ch = getchar()) != '\n')
    {
    
    
      ;
    }
    //
    
    printf("确认密码(Y/N)>:");
    ch = getchar();
    …… 
}

程序分析:getchar读取余下的字符,若ch!=’\n’,什么都不做,只是取走,再回到判断部分,直到遇到\n,\n!=’\n’为假,跳出循环.此时\n已被取走,缓冲区清理完毕.

2.for语句

语法结构:

for(表达式1; 表达式2; 表达式3)
    循环语句;//(默认控制一条语句)
表达式1:初始化部分
表达式2:条件判断部分
表达式3:调整部分

和while语句相比:
①for语句三个部分集中,便于更改,优于while语句
②当使用continue时,while语句需要判断continue和调整语句的相对位置来决定是否执行调整语句;而for语句,则一定会执行调整语句.

int main()
{
    
    
  int i = 0;
    for(i=1;i<=10;i++)
    {
    
    
      if(5==i)//当5==i,continue跳出本次循环,接着执行i++
        {
    
    
          continue;
        }
        printf("%d",i);
    }
}//输出结果为1234678910
  • for语句的建议:
    ①不可在for循环体内改变循环变量
int main()
{
    
    
  int i = 0;
    for(i=1;i<=10;i++)
    {
    
    
      if(i = 5)
          printf("%d",i);
    }
    return 0; 
} //此时程序运行结果为死循环打印5

②建议初始化部分和条件判断部分采取"前闭后开"写法.
如for( i = 0;i < 10; i++),指明0到9,10个元素.

  • for语句的变形:
    变形①:省略初始化,条件判断,调整三部分
	for (; ; )
	{
    
    
		printf("haha");
		return 0;
	}
	//死循环打印haha

语法上可以省略,但当省略条件判断部分,那判断部分恒为真,进入死循环.

变形②:初始化,条件判断,调整三部分可以是一条语句,也可多条.

int x, y;
    for (x = 0, y = 0; x<2 && y<5; ++x, y++)
   {
    
    
        printf("hehe\n");
   }
 return 0;

变形③:省略初始化部分

int main()
{
    
    
  	int i = 0;
    int j = 0;
    for( ; i < 10 ; i++)
    {
    
    
      for( ; j<10 ; j++)
        {
    
    
          printf("hello\n");
        }
    }
}

程序分析:
①i=0且i<10进入内层循环,从j=0到j=10打印了10次hello后跳出内层循环.
②i++后i=1且i<10,但此时j=10(没有初始化),则后续i一直自增但不会再打印.

下面为关于for的一道面试题:判断循环的次数

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

0次,k=0为赋值语句,为假,不执行.

3.do while语句

语法结构:

do
{
    
    
	循环语句;
}while(表达式)

do…while语句至少执行一次,使用场景有限,少用.

实例:

int main()
{
    
    
  int i=1;
    do{
    
    
        printf("%d",i);
      i++;
    }while(i<=10);
    return 0;
}//打印1-10

在do…while语句中使用continue,continue会跳过后面的语句来到while的判断部分(类似在while语句中),需要根据continue和调整部分的相对位置来决定是否执行.

练习:
1.计算n的阶乘
2.计算1!+2!+3!+……+10!
3.再一个有序数组中查找具体的某个数字n。编写int binsearch(intx,intv[],int n);功能:再v[ 0 ]<=v[1]<=v[2]<=…<=v[n-1]的数组中查找x
4.编写代码,演示多个字符从两端移动,向中间汇聚
5.编写代码实现,模拟用户登录情景,并且只能登录三次。(值允许输入三次密码,如果密码正确则提示成功,如果三次均输入错误,则退出程序)

1.计算n的阶乘

#include<stdio.h>
int main()
{
    
    
	int n, i, ret = 0;
	scanf("%d", &n);

//方法一:while语法
	//ret = 1;
	//i = 1;
	//while (i <= n)
	//{
    
    
	//	ret *= i;
	//	i++;
	//}
	//printf("%d", ret);

//方法二:for语法
//	for (ret = 1, i = 1; i <= n; i++)
//	{
    
    
//		ret *= i;
//	}
//	printf("%d", ret);

//方法三:do while语法
	ret = 1;
	i = 1;
	do
	{
    
    
		ret *= i;
		i++;
	} while (i <= n);
	printf("%d", ret);

	return 0;
}

2.计算1!+2!+3!+……+10!

#include<stdio.h>
int main()
{
    
    
//方法一:
	//int n, i, j, ret = 0;
	//int sum = 0;
	//scanf("%d", &n);

	//for (i = 1; i <= 10; i++)
	//{
    
    
	//	ret = 1;
	//	for (j = 1; j <= i; j++)
	//	{
    
    
	//		ret *= j;

	//	}
	//	sum += ret;
	//}
	//printf("%d", sum);
	//return 0;
//方法一实现了阶乘求和,但每次阶乘都得从1开始乘,效率较低

//因为n!=((n-1)!)*n,即4!=3!*4
//方法二:
	int n, i = 0;
	int sum = 0;
	int ret = 1;
	scanf("%d", &n);

	for (i = 1; i <= n; i++)
	{
    
    
		ret *= i;
		sum += ret;
	}
	printf("%d", sum);
	return 0;
}

3.在一个有序数组中查找具体的某个数字n.
普通的方法:

#include<stdio.h>
int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
    
    
		if (k == arr[i])
		{
    
    
			printf("找到了,他的下标为%d", i);
			break;
		}
	}
	if (i == sz)
	{
    
    
		printf("找不到\n");
	}
	return 0;
}

分析:显然逐一查找效率很低,当从1-10000中找到9999则要花费很长时间.面对有序数组(可由冒泡排序得到),我们可以用二分查找法(折半查找法)

二分查找法:

//二分查找法/折半查找法
#include<stdio.h>
int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	int left = 0;//最左边元素下标
	int right = sz - 1;//最右边元素下标

	while (left<=right)
	{
    
    
		int mid = (left + right) / 2;//中间元素下标
		if (k > arr[mid])//比较中间元素和目标元素
		{
    
    
			left = mid - 1;
		}
		else if (k < arr[mid])
		{
    
    
			right = mid - 1;
		}
		else
		{
    
    
			printf("找到了,他的下标为%d\n", mid);
			break;//找到目标元素后跳出循环
		}
	}
	if (left > right)
	{
    
    
		printf("找不到\n");
	}
	return 0;
}

4.编写代码,演示多个字符从两端移动,向中间汇聚

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<Windows.h>
int main()
{
    
    
	char arr1[] = "i am a handsome boy";
	char arr2[] = "###################";

	int left = 0;
	int right = strlen(arr1) - 1;//stelen计算字符不会把'\0'算进去

	//int right = ( sizeof(arr1) / sizeof(arr[0]) )- 1;这是错误写法.arr1最后一个字符是'\0'
	//int right = ( sizeof(arr1) / sizeof(arr[0]) )- 2;正确,但不推荐,容易出错

	while (left <= right)
	{
    
    
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		left++;
		right--;
		Sleep(1000);
		system("cls");
	}
	printf("%s\n", arr2);
	return 0;
}

Sleep()函数:
让屏幕休息一段时间,如Sleep(1000),可让屏幕休息1000ms,即1s.其头文件为Windows.h
system()函数:
执行系统命令,如system(“cls”); 为执行系统命令中的一个函数,其作用为清空屏幕,其头文件为stdlib.h

5.编写代码实现,模拟用户登录情景,并且只能登录三次。

#include<stdio.h>
int main()
{
    
    
	char arr[] = "123456";
	char password[21] = "";
	int i = 0;

	printf("请输入密码:\n");
	for (i = 0; i < 3; i++)
	{
    
    
		scanf("%s", password);
		if (0 == strcmp(arr, password))
		{
    
    
			break;
		}
		else
		{
    
    
			printf("密码错误,请重新输入:\n");
		}
	}
	if (3 == i)
	{
    
    
		printf("输入次数用尽");
	}
	else
	{
    
    
		printf("登陆成功");
	}
	return 0;
}

注意:

if (password == arr)

这是错误写法.passwor和arr都是数组的数组名,表示数组的地址,这里比较的是两个数组的地址,显然是不相同的。
比较两个字符串应该使用strcmp()函数:
在这里插入图片描述

4.goto语句

语法结构:

C语言提供goto和标记跳转的标号,来改变程序流向,转到执行语句标号所标识的语句.
goto语句用途:终止程序在某些深度嵌套的结构的处理过
程,例如一次跳出两层或多层循环.而break只能从某层循环跳到上一层循环.但goto不可跨函数跳转.
使用例子:

int main()
{
    
    
again:
    printf("hello\n");
    goto again;  //是代码跳到again的位置,此时程序会进入死循环
    return 0;
}

下面是有趣的使用goto的关机程序:
提示:
程序运行开始倒计时,若在1min内,输入"我是猪",则取消关机;
否则,嘿嘿嘿~

shutdown -s -60 系统在60秒后关机
代码为:system(“shutdown -s -t 60”);
shutdown -a 取消关机
代码为:system(“shutdown -a”);
两者得包含在头文件stdlib.h里

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    
    
	char input[20] = {
    
     0 };
	system("shutdown -s -t 60");

again:
	printf("关机程序已开始,若输入:我是猪,将取消关机,请输入:\n");
	scanf("%s", input);
	if (0 == strcmp(input, "我是猪"))
	{
    
    
		system("shutdown -a");
		printf("成功取消关机");
	}
	else
	{
    
    
		printf("输入有误,请重新输入");
		goto again;
	}
	/*
	while语句写法:
	while (1)
	{
		printf("关机程序已开始,若输入:我是伞兵,将取消关机,请输入:\n");
		scanf("%s", input);
		if (0 == strcmp(input, "我是伞兵"))
		{
			system("shutdown -a");
			break;
		}
		else
		{
			printf("输入有误,请重新输入");
		}
	}
	*/
	return 0;
}

以Release的形式生成的.exe程序可以发给别人,也可以将该程序放进计算机自动启动的程序中。

猜你喜欢

转载自blog.csdn.net/weixin_50614301/article/details/121054140