4444。c语言逻辑控制详解。
+a的结果是2,非0,为真,所以if后的表达式为真,会输出冬季。for循环的执行顺序,第一次是表达式1,表达式2,循环体,表达式3。之后就是表达式2,循环体,表达式3,表达式1就没了,只用于变量的初始化。所以i到了5之后,就永远不会执行到i = i + 1那里了,永远都是5了,绕进去了。是执行顺序没有理解好的问题。原因是定义的变量类型是字符,空格和回车也是字符,就把空格和回车赋进b里去了,输入的那
顺序结构
程序从上往下运行。运行的结果跟你写的顺序有关系。
选择结构
if语句
语法形式1
if(表达式)
{
语句;
}

如果表达式(条件)为真,就执行语句。如果是假,就结束了。
花括号一定要写。
eg.输入一个整数,判断它是否为奇数。
int a;
scanf("%d",&a);
if(s % 2 == 1)
{
printf("%d是奇数\n",a);
}
如果表达式是真的就会执行花括号里面的。
注意if的小括号后面不要加分号。不要 加 分号。
if的花括号一定要记得写。因为不写花括号默认if下面的只有一行语句。要写多行语句一定要记得加花括号。为了保证可读性请一定要 加 花括号。
如果考试考了那就是只是为了考试而已。
语法形式2
if(表达式)
{
语句1;
}
else
{
语句2;
}
如果表达式为真就执行语句1,否则执行语句2。
eg.输入一个整数,判断是否为奇数。如果是奇数打印奇数,否则打印偶数。
int a;
scanf("%d",&a);
if(s % 2 == 1) //注意是两个等号。
{
printf("%d是奇数\n",a);
}
else
{
printf("%d是偶数\n",a);
}
如果是要多组输入的话就用一个while,把scanf放进去。
while(scanf("%d",a) != -1)
{
if else巴拉巴拉的
}
语法形式3
if(表达式1)
{
语句1;
}
else if(表达式2)
{
语句2;
}
else
{
语句3;
}
有一个东西。 n >= 5 && n < 10。&&是同时,并且的意思。
逻辑运算符
!逻辑取反
!真——>假
int a = 1;
printf("%d\n",!a); //0。c语言里,非0代表真,0代表假。
a !a
非0 0
0 1
&&逻辑与
表达式1 && 表达式2
都真才真,一假全假。(联言判断)
a b a&&b
非0 非0 1
非0 0 0
0 非0 0
0 0 0
示例:输入一个月份,如果是在3月到5月之间则输出春季。
短路与 表达式1 && 表达式2
如果表达式1为假,就不去判断表达式2了。
if(month >= 3 && month <= 5)
如果month >= 3不成立,就不会执行month <= 5的表达式。
|| 逻辑或
有真就真,都假才假。(相容选言判断)
a b a||b
非0 非0 1
非0 0 1
0 非0 1
0 0 0
示例:输入一个月份,如果是在12月或者1月或者2月则输出冬季。
if(month == 12 || month == 1 || month == 2)
短路或:如果表达式1为真,就不执行表达式2了。
int month;
int a = 1;
scanf("%d",&a);
if(month == 12 || ++a)
{
printf("冬季\n");
}
printf("%d\n",a);
如果输入的是12,那最后会输出冬季还有1,a的值还是1。因为短路或,如果第一个表达式是真就不会执行第二个表达式了。因为month == 12为真所以不会执行++a。
如果输入的是10,那最后会输出冬季还有2。首先month == 12不满足,所以会继续往下执行表达式2。++a的结果是2,非0,为真,所以if后的表达式为真,会输出冬季。同时运算过后的a现在的值是2。
练习:输入一个年份,判断是不是闰年。
思路:闰年的判断方法:
普通闰年:能被4整除但是不能被100整除的年份是闰年。
世纪闰年:能被400整除的年份是闰年。
if((year % 4 == 0) && (year % 100 != 0))
else if(year % 400 == 0)
else
代码可以合并
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
else
老师说加括号是为了确保逻辑清晰所以还是加上吧加上又不会错。
switch语句
是一种特殊形式的if else结构,用于判断条件有多个确定结果的情况。它把多重的else if改成更易用,可读性更好的形式。
switch(整型表达式) //字符型,整型。浮点型就不行。
{
case 整型常量1: 语句;
case 整型常量2: 语句;
......
default: 语句;
}
示例:输入一个数据,根据数据的值进行匹配。
int num;
scanf("%d",&num);
switch(num)
{
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
default:
printf("输入有误\n");
}
能不能不写break。如果case1后面不写break,输入了1。理论上应该要输出1,但是会发现输出的是1和2。是因为没有break的话会去找下一个break。break的作用是,当你匹配到了某一个case之后,这个switch就结束了。如果没有break,就会一直往后走直到找到下一个break。
不加也有应用。
int num;
scanf("%d",&num);
switch(num)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("工作日\n");
break;
case 6:
case 7:
printf("周末\n");
break;
default:
printf("输入错误\n");
break;
}
一般用if会多一点。后面有例子。
循环结构
while循环
while(表达式)
{
语句;
}
条件为真时重复执行代码,适合循环次数未知的场景。(不是硬性要求)
示例:在屏幕上打印1-10的值。
int i = 1;
while(i <= 10)
{
printf("%d\n",i);
i++;
}
注意:初始化条件(i = 1) 判断条件(i <= 10) 条件的变化(i++)缺一不可
小心变成死循环。
如果初始条件为假,循环体一次也不执行。
练习1:输入一个正的整数,逆序打印这个整数的每一位。
1234——>4 3 2 1 521——>1 2 5
思路:123——>3 2 1 个位十位百位
怎么拿到各位数字3
十进制
123%10=3 123/10=12
12%10=2 12/10=1
1%10=1 1/10=0
0 结束
循环
// int main()
// {
// int n;
// scanf("%d",&n);
// while(n != 0)
// {
// printf("%d ",n % 10); //3 2 1
// n = n / 10; //12 1 0
// }
// return 0;
// }
总结:要拿到十进制数的每一位,先%10后/10。同理,要拿到二进制数的每一位,先%2后/2。
练习2:求5的阶乘。
思路:要拿到1到5的所有整数。
// int main()
// {
// int n;
// scanf("%d",&n);
// int i = 1;
// int ret = 1;
// while(i <= n)
// {
// ret = ret * i; //规定一个变量积累累乘的乘积。
// i++;
// }
// printf("%d\n",ret);
// return 0;
// }
讲了一个问题。
char a;
scanf("%c",&a);
char b;
scanf("%c",&b);
printf("%c,%c\n",a,b);
这个时候会发现一个事情。如果输入的是a b(中间有一个空格),输出的结果会是a,(没有b)。如果输入的是a回车,输出的结果还是a,(没有b)。
原因是定义的变量类型是字符,空格和回车也是字符,就把空格和回车赋进b里去了,输入的那个b就相当于没用。
解决这个问题的方法是getchar。把程序变成
char a;
scanf("%c",&a);
getchar(); //作用是把空格或者回车吸收进去。几个getchar几个空格。
char b;
scanf("%c",&b);
for循环
已知循环次数时使用,三种循环中使用最多的,适合遍历数组或集合。
for(表达式1;表达式2;表达式3)
{
循环体语句;
}
表达式1用于循环条件初始化,表达式2用于循环结束时条件的判断,表达式3用于循环变量的调整。
for循环的执行顺序,第一次是表达式1,表达式2,循环体,表达式3。之后就是表达式2,循环体,表达式3,表达式1就没了,只用于变量的初始化。
int i = 1;表达式1
while(i <= 10) 表达式2
{
printf("%d\n",i);
i++; 表达式3
}
变成for循环就是
for(int i = 1; i <= 10;i = i + 1) //要写那个定义变量的int。还有就是i = i + 1可以写成i++。
{
printf("%d\n",i);
}
练习:求1到100之间2的倍数的数之和。
// int main()
// {
// int sum = 0;//存和
// for(int i = 1; i <= 100; i++)
// {
// if(i % 2 == 0)
// {
// sum = sum + i;
// }
// }
// printf("%d\n",sum); //在循环外面打印
// return 0;
// }
do-while循环
用的最少,保证循环体至少被执行一次。
do
{
循环体语句;
}
while(表达式); //跟其他的区分,分号必须要写。
do-while是先斩后奏来的。很少用。
循环嵌套
练习:打印九九乘法表
思路:i*j=n
int main()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
printf("%d*%d=%d",i,j,i*j);
}
}
return 0;
}
结果对。格式不对。而且多了。
改
int main()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= i; j++) //重复的不用打印
{
printf("%d*%d=%2d ",j,i,i*j); //一位数字右对齐。式子之间加空格。两个乘数换顺序。
}
printf("\n"); //换行
}
return 0;
}
总结:先写再改。
示例:求一个整数存储再内存中的二进制中1的个数。
思路1:按位与。
0000 0101
0000 0001
——————
1
& 按位与1。最后一位结果是1原数字最后一位就是1,结果是0原数字最后一位就是0.然后原数字右移一位,再与1,跟上一次同理。
直到原数字全部为0了,就没有与的必要了。
问题:负数不行。符号位是1,不会全0,死循环。
思路2:要解决负数的问题。虽然负数不会变成全0,但是已知int有32个比特位,所以只要控制右移只进行三十一回就可以了。
思路3:再优化。
0000 0111 7
0000 0110 6
——————
0000 0110 6
0000 0101 5
——————
0000 0100 4
0000 0011 3
——————
0000 0000 0
num & (num -1)
每这样与一次,结果的二进制数里就少一个1。
break和continue
立即终止并跳出当前所在循环。
跳过本次循环尚未执行的语句,直接开始下一次循环的判断和执行。
while(i <= 10)
{
if(i == 5)
{
break;
}
printf("%d\n",i);
i++;
}
这个到i==4就停了。
输出结果是1 2 3 4。
练习:找到1-100之间第一个能被3整除的数。
while(i <= 10)
{
if(i == 5)
{
continue;
}
printf("%d\n",i);
i++;
}
把break换成continue了,代码死循环了。
continue是它下面的代码不执行了,重新开始循环。所以i到了5之后,就永远不会执行到i = i + 1那里了,永远都是5了,绕进去了。
while(i <= 10)
{
if(i == 5)
{
i++;
continue;
}
printf("%d\n",i);
}
把i++放在continue上面,输出的结果就是1 2 3 4 6 7 8 9 10,没有5。因为等于5的时候不往下printf了,相当于把5那次循环跳过了。
break和return 0有什么区别。
break只用于循环和switch,return 0用于结束函数。两个用处不一样。
for(int i = 1; i <= 10; i++)
{
if(i == 5)
{
continue;
}
printf("%d\n“,i)
}
输出的结果还是1 2 3 4 6 7 8 9 10。。。我以为会死循环的。。为什么。。。
我明白了。是执行顺序没有理解好的问题。for循环的第三个表达式本来就是在循环节执行结束之后再执行的。所以在continue之外。
要区分while循环和for循环。
练习:找到1-100之间所有能被3整除的数,要求使用continue。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)