我们学习编程的目的,其实就是让电脑帮我们做事。要想电脑能很好地、高效地为我们服务,就得学习一个重要知识点“程序控制结构”。比如我们要从1一直加到1000。如果我要输成百上千次加法运算,就有点不合适。学了程序控制结构后,我们只需要输入两三句语句就0k了。比如:
int j=0;
for (int i=1;i<=1000;i++)
{
j+=i;
printf("i=%d,j=%d\n",i,j);
}
【数据结构】
一、C语言的结构
顺序结构,代码从上到下执行
分支结构/选择结构
循环结构
二、分支结构
【1】if单分支结构
if(表达式)
{
表达式成立执行的代码块;
}
【2】双分支结构
if(表达式)
{
表达式成立执行的代码块;
}
else
{
表达式不成立执行的代码块;
}
【3】多分支结构
if(表达式1)
{
表达式1成立执行的代码块;
}
else if(表达式2)
{
表达式1不成立但是表达式2成立执行的代码块;
}
else if()
{
····
}
····
else
{
}
【4】嵌套if
if(表达式1)
{
if(表达式2)
{
表达式1成立并且表达式2成立执行的代码块;
}
else
{
表达式1成立但是表达式2不成立执行的代码块;
}
}
else if( ····)
·····
例如:
1、终端输入年份,判断是否是闰年,能被四整除但是不能被100整除或者能被400整除的叫闰年。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num;
scanf("%d",&num);
//判断是否是偶数
if(num%2==0)
{
printf("%d是二的倍数\n",num);
}
else
{
printf("%d不是二的倍数\n",num);
}
printf("请输入新的数\n");
scanf("%d",&num);
if(!(num%7)) //!是一个单目运算符,优先级高于%
{
printf("%d是七的倍数\n",num);
}
else
{
printf("%d不是七的倍数\n",num);
}
printf("请输入年份\n");
scanf("%d",&num);
if(num%4==0&&num%100!=0||num%400==0)
{
printf("%d年是闰年\n",num);
}
else
{
printf("%d是平年\n",num);
}
return 0;
}
2、终端输入一个[100,999]之间的数,判断是否是是否是水仙花数,
(水仙花数:个位*个位*个位+十位*十位*十位+百位*百位*百位=数本身)
#include <stdio.h>
#include <math.h>
int main(int argc, const char *argv[])
{
int num,a,b,c;
printf("请输入一个数\n");
scanf("%d",&num);
a = num/100;
b = num/10%10;
c = num%10;
//使用pow函数需要包含<math.h>头文件,gcc编译需要加上-lm参数
if(num==a*a*a+b*b*b+pow(c,3))
{
printf("%d是一个水仙花数\n",num);
}
return 0;
}
3、终端输入学生成绩,输出成绩等级,[100,90]A,(90,80]B,(80,70]C,(70,60]D,(60,0]不及格。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int score;
scanf("%d",&score);
if(score<0||score>100)
{
printf("error\n");
}
else if(score>=90&&score<=100)
{
printf("A\n");
}
else if(score>=80&&score<90)
{
printf("B\n");
}
return 0;
}
4、狗的前两年每一年相当于人类的10.5岁,之后每增加一年就增加一岁,终端输入狗的年龄,输出该相当于人的多少岁。
#include <stdio.h>
int main(int argc, const char *argv[])
{
float age;
scanf("%f",&age);
if(age>2) //判断狗的年龄是否大于2,大于2时的计算逻辑
{
age = 10.5*2+age-2;
}
else //小于等于2时的计算逻辑
{
age = 10.5*age;
}
printf("%f\n",age);
return 0;
}
5、终端输入一个数,判断是否是3的倍数,如果是3的倍数再判断是否是5的倍数。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num;
scanf("%d",&num);
if(num%3==0&&num!=0)
{
if(num%5==0)
{
printf("%d既是3的倍数也是5的倍数\n",num);
}
else
{
printf("%d是3的倍数但是不是5的倍数\n",num);
}
}
return 0;
}
6、终端输入三条边,判断是否能构成三角形(判断两边之和大于第三边),在能构成三角形的基础上判断三角形的类型(等边,等腰和直角)
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a+b>c&&a+c>b&&c+b>a) //两边之和大于第三边,能构成三角形
{
if(a==b||b==c||a==c) //是否是等腰三角形
{
if(a==b&&b==c) //说明三边相等
{
printf("能构成等边三角形\n");
}
else
{
printf("能构成等腰三角形,但不能构成等边三角形\n");
}
}
if(a*a+b*b==c*c||c*c+b*b==a*a||a*a+c*c==b*b)
{
printf("能构成直角三角形\n");
}
}
return 0;
}
7、从终端输入一个字符:如果是大写的 转换成小写,如果是小写的 转换成大写,如果是 0-9 按照 %d 输出对应整型的 0-9,其他字符 转换成 #并输出。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char c;
scanf("%c",&c);
if(c>='A'&&c<='Z')
{
c = c+32; //把大写字母转成小写字母
printf("%c\n",c);
}
else if(c>='a'&&c<='z')
{
c-=32;
printf("%c\n",c);
}
else if(c>='0'&&c<='9')
{
printf("%d\n",c-48);
}
else
printf("#\n");
return 0;
}
小总结:if···else的注意事项
1。else前面必须有一个if
2。if后面如果只有一条语句可以不加{},如果有多条语句一定要加{},else同理
3。if后面通常放的是条件运算表达式/逻辑运算的表达式/变量/赋值语句····,只要有明确结果的表达式都可以放在()里。
4。由于if的条件中,可以放赋值语句,在判断相等时if(a==1)建议写成if(1==a)
【5】switch····case分支
格式:
switch(变量)
{
case 常量表达式:
语句块1;
break;
case 常量表达式:
语句块2;
break;
····
case 常量表达式:
语句块n;
break;
default:
语句块n+1;
break;
}
switch和后面括号内的内容是,选择的变量,case后面的常量表达式,就是switch后面的变量可能出现的情况。
哪个case后面的常量是变量的结果,就执行哪个case后面的代码块。
switch···case的执行逻辑
进入switch···case判断变量的结果,和case后的常量表达式判断,走满足的case后面的分支。如果一个case后面没有break,执行完该case后会顺序向后执行下面的case/switch···case语句。default的作用,如果不关心其他分支,就写一个default,其他分支就走default
使用switch···case的注意事项
1、switch后面的变量只能是char/int
2、如果不加break会顺序向后执行,叫做case击穿
3、case的顺序,不会影响程序的执行
4、default的位置也不会影响程序的执行,只有所有case都不满足时,才会走default分支
5、case击穿可以根据使用场景的不用利用起来。
练习:
1、终端输入学生成绩,输出成绩等级,[100,90]A,(90,80]B,(80,70]C,(70,60]D,(60,0]不及格,使用switch····case完成。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int score;
scanf("%d",&score);
int a = score/10;
if(score>=0&&score<=100) //判断成绩合理性
{
switch(a)
{
case 10:
//利用了case击穿,让case10和case9走同一个分支
case 9:
printf("A\n");
break;
case 8:
printf("B\n");
break;
case 7:
printf("C\n");
break;
case 6:
printf("D\n");
break;
case 5||4||3||2||1: // <==>case 1:
//5||4||3||2||1 是一个逻辑或运算的表达式,是一个常量表达式,结果是1
printf("不及格\n");
}
}
else
{
printf("error\n");
}
return 0;
}
2、使用switch···case完成简易计算器功能(+、-、*、/、%),如3+5输出8,只完成个位数的计算
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num1,num2; //两个操作数
char a; //运算符
scanf("%c%d%d",&a,&num1,&num2);
//switch用于判断操作符
switch(a)
{
case '+':
printf("%d+%d=%d\n",num1,num2,num1+num2);
break;
case '-':
printf("%d-%d=%d\n",num1,num2,num1-num2);
break;
case '*':
printf("%d*%d=%d\n",num1,num2,num1*num2);
break;
case '/':
printf("%d/%d=%f\n",num1,num2,(float)num1/num2);
//除法时,将其中一个整形数据强转成float类型
break;
case '%':
printf("%d%%%d=%d\n",num1,num2,num1%num2);
//想输出一个%需要在""内打两个%%
break;
}
return 0;
}
3、终端输入年月日,输出是这一年的第几天,如2023.3.1输出60,需要考虑闰平年,2月闰年29,平年28。
1 3 5 7 8 10 12 都是31天
#include <stdio.h>
int main(int argc, const char *argv[])
{
int year,month,day;
scanf("%d%d%d",&year,&month,&day);
switch(month)
{
case 12:
day = day+30;
case 11:
day = day+31;
case 10:
day = day+30;
case 9:
day = day+31;
case 8:
day = day+31;
case 7:
day = day+30;
case 6:
day = day+31;
case 5:
day = day+30;
case 4:
day = day+31;
case 3:
//day = day+28; //二月统一+28天,在switchcase外判断闰平年再加1
//在switch```case的里面嵌套if判断
if(year%4==0&&year%100!=0||year%400==0)
{
day = day + 29;
}
else
{
day = day+28;
}
case 2:
day = day+31;
case 1:
break;
}
/*if(year%4==0&&year%100!=0||year%400==0)
{
day+=1;
}*/
printf("%d\n",day);
return 0;
}
三、循环结构
【1】while循环
格式:
while(条件)
{
代码块;
改变循环变量的语句;
}
先判断条件是否成立,如果条件成立,执行代码块里的语句
再判断条件是否成立,如果不成立退出while循环
注意:
1、循环的次数,只和循环变量初始值、步长以及循环条件有关。
2、如果while后面,只有一条语句,{}可以不写
3、while()后面不要加;
while(1){}死循环
练习:
1、使用while循环输出5行helloworld。
#include <stdio.h>
int main()
{
int i = 2;
while(i<=10)
{
printf("hello world\n");
i+=2; //让循环变量每次自增2
}
}
2、1-100中的偶数
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i = 1; //循环变量的初始值
while(i<=100)
{
if(i%2==0)
{
printf("%d是偶数\n",i);
}
i++; //改变循环变量的语句
//步长:循环变量的改变方式
}
return 0;
}
或者
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i = 2;
while(i<=100)
{
printf("%d\n",i);
i+=2; //i的步长是2
}
return 0;
}
3、求1-100的和,5050。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i = 1,sum =0; //分别给循环变量和sum赋初值
while(i<=100)
{
sum+=i;
i++; //改变循环变量
}
printf("%d\n",sum);
return 0;
}
4、输出100-999内的所有水仙花数,(各位的三次方相加等于该数)
使用pow函数,需要加编译选项-lm。
#include <stdio.h>
#include <math.h>
int main(int argc, const char *argv[])
{
int num = 100,a,b,c;
while(num<=999) //while(i<1000)
{
a = num/100;
b = num/10%10;
c = num%10;
if(pow(a,3)+pow(b,3)+pow(c,3)==num)
//pow的使用方式pow(数,幂次),gcc -lm
{
printf("%d是一个水仙花数\n",num);
}
num++;
}
return 0;
}
5、猴子吃桃问题,猴子第一天摘了若干个桃,
当即就吃了一半的桃,没过瘾,又多吃一个
第二天,在剩下的桃里吃了一半的桃,没过瘾,又多吃一个
依次类推,知道第10天,猴子发现只剩一个桃了。
问:猴子第一天摘了几个桃子。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int peach = 1,i=9; //i进入循环时是第9天,第9天的桃子数才需要去计算
while(i>=1) //循环进行9次
{
peach=(peach+1)*2;
i--; //改变循环变量
}
printf("%d\n",peach);
return 0;
}
【2】do···while循环
先执行再判断
do
{
循环体;
}while(条件);
先执行循环体语句,再判断条件是否成立。
do···while语句不管条件是否满足,循环体内语句都会执行一次。
【3】for循环
【1】格式
for(表达式1;表达式2;表达式3)
{
(循环体内)代码块;
}
先执行表达式1,表达式1通常是循环变量初始化语句,
再执行表达式2,表达式2是for循环判断条件,
如果条件成立,执行循环体内的语句,再执行表达式3,表达式3就是循环变量的步长
如果条件不成立,退出for循环.
练习
1、求1-100内奇数的和。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i,sum=0;
for(i=1;i<=100;i++) //i=1,只会执行一次,i++执行的次数和循环次数一致
{
if(i%2!=0)
{
sum+=i;
}
}
//循环结束,说明奇数和求完了
printf("%d\n",sum);
return 0;
}
2、终端输入一个数,求该数的所有因子,如12,输出1 2 3 4 6 12
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num;
scanf("%d",&num);
int i;
for(i=1;i<=num;i++) //循环从1-num的每一个数
{
if(num%i==0) //判断循环到的数是否是num的因子
{
printf("%d\n",i);
}
}
return 0;
}
3、输出下三角的九九乘法表
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i,j;
for(i=1;i<=9;i++) //外层循环控制行数
{
for(j=1;j<=i;j++) //内层循环控制每行打印的列数
{
printf("%d*%d=%d\t",j,i,i*j);
}
printf("\n"); //每一行打印完输出换行
}
return 0;
}
四、goto 跳转
【1】goto的基本使用
goto的本质是代码跳转,也可以用它实现循环,只能在同一个函数中跳转。
尽量不要在代码中使用goto,降低代码的可读性
语句块1;
goto NEXT; //NEXT就是一个标签
语句块2;
语句块3;
NEXT:
语句块4;
执行逻辑:
先执行语句块1,接着走到goto,跳转到goto后面的标签,执行语句块4
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 100;
goto NEXT;
printf("%d\n",a);
NEXT:
// int b = 9; //把变量的声明放在goto的标签里面
printf("*******\n");
int b = 9;
printf("%d\n",b);
return 0;
}
【2】使用goto实现循环
如果想要使用goto实现循环,需要把标签放在goto的上面,这样就会一直执行goto
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 100;
goto NEXT;
printf("%d\n",a);
NEXT:
// int b = 9; //把变量的声明放在goto的标签里面
printf("*******\n");
int b = 9;
printf("%d\n",b);
return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 9;
NEXT:
printf("%d\n",a);
goto NEXT;
return 0;
}
//使用goto实现循环输出5行hello world
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 1;
NEXT:
printf("hello world\n");
a++;
//循环条件,如果没有判断一直goto就死循环了
if(a<=5)
{
goto NEXT; //使用goto打印的hello world有4个
//第一次进入if判断的a=2
}
return 0;
}
练习:
1、使用goto实现1-100的求和
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i = 1,sum=0;
LOOP:
sum+=i; //先让sum计数
i++; //再让循环变量自增
if(i<101)
{
goto LOOP;
}
printf("%d\n",sum);
return 0;
}
辅助控制关键字
return break continue
【1】break
break只能用在循环和switch···case中,不能再goto中使用
break用在循环中,表示退出本层循环。
for循环
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i,j;
for(i=1;i<4;i++)
{
printf("i=%d\t",i);
for(j=1;j<5;j++)
{
if(j==3)
{
//break; //跳出本层循环
continue; //跳出本层本次循环
//return ; //退出当前函数
}
printf("j=%d\t",j);
}
printf("\n");
}
return 0;
}
while循环
#include <stdio.h>
int main(int argc, const char *argv[])
{
int i=1,j=1;
while(i<4)
{
printf("i=%d\t",i);
j=1; //让内层循环变量j,每一次进入循环前都重置一次
while(j<5)
{
if(j==3)
{
//break; //跳出本层循环
//continue; //跳出本层本次循环,死循环,因为j永远=3
return 1;
}
printf("j=%d\t",j);
j++;
}
printf("\n");
i++;
}
return 0;
}
【2】continue
退出本层本次循环,不能再goto中使用
continue放在while中时,需要把修改循环变量的语句放在continue的上面
【3】return
退出当前函数