【C】3、条件与循环
一、if条件语句
1、单个if
if 括号里的是条件,只有当括号里面的条件满足了,才会执行大括号里面的。
这里的满足条件,换句话说就是条件为真,这个条件为真我们有时候会用数字来表示,通常使用1和0来分别表示真假。
if括号里面的条件有时候很喜欢跟逻辑关系一起运用,这个里面是存在“短路”的,具体来说,是或逻辑的条件语句中,第一个满足条件了,就不会执行后面的条件。
这是一个普通的简单的if条件语句:
#include <stdio.h>
int main(void)
{
if(1 + 1 == 2)
{
printf("true!\n");
}
return 0;
}

条件用数字表示的情况:
#include <stdio.h>
int main()
{
if (1)
{
printf("大帅批!\n");
}
if (0)
{
printf("啊对对对!\n");
}
return 0;
}

关于那个短路的情况:
#include <stdio.h>
int main()
{
if (1 || printf("hello\n"))
{
printf("大帅批!\n");
}
return 0;
}

2、多个if
运用多个 if 条件,使其包含多种可能,这些条件随着程序从上到下顺序依次执行,用的时候区分于if-else,if-else只执行if或者else中的一个。
// 输出分数,并给分数评定等级
#include <stdio.h>
int main(void)
{
int a;
printf("请输入分数:\n");
scanf("%d",&a);
if(a >= 90 && a <= 100)
{
printf("等级:A,优秀\n");
}
if (a >= 80 && a <= 90)
{
printf("等级:B,良好\n");
}
if (a >= 70 && a <= 80)
{
printf("等级:C,一般\n");
}
if (a >= 60 && a <= 70)
{
printf("等级:D,及格\n");
}
if (a < 60)
{
printf("等级:E,不及格\n");
}
if(a > 100)
{
printf("输入错误!");
}
return 0;
}

3、if else
满足if的条件就执行if的大括号里面的,不满足则执行else的,
而一旦形成了if-else ,两个代码块的中间就不能插入其他代码块了,额,你在这中间空格几行其实是没啥问题的,,,
#include <stdio.h>
int main(void)
{
int a;
printf("请输入a的值:\n");
scanf("%d",&a);
if(1 + 1 == a)
{
printf("true!");
}
else
{
printf("false!");
}
return 0;
}
4、else if
else-if 并不是单独使用的,在他前面,一定会有if。而假如后面还跟了一个else的话,那么else后面的条件,默认是相邻的那个 if 的补集。
// 输出分数,并给分数评定等级
#include <stdio.h>
int main(void)
{
int a;
printf("请输入分数:\n");
scanf("%d",&a);
if(a > 100)
{
printf("输入错误!");
}
else if(a >= 90)
{
printf("等级:A,优秀\n");
}
else if(a >= 80)
{
printf("等级:B,良好\n");
}
else if(a >= 70)
{
printf("等级:C,一般\n");
}
else if(a >= 60)
{
printf("等级:D,及格\n");
}
else
{
printf("等级:E,不及格\n");
}
return 0;
}
5、if的判断条件会被执行一次
之前万万没想到一点,就是if判断条件中的语句,其实会被执行一次。遇见这个问题的时候已经属于被坑了,此时我刚刚从标准IO的fclose中回头来,
错误情况:
fclose(Fd_1);
if (EOF == fclose(Fd_1))
{
perror("fclose file failed:");
}
这一个程序段是我计划用来关闭刚刚打开的文件的,在我的设想中,后面的按个if用来检验关闭成功了没,就好比如还有一个if来判断打开成功了没,
但这里不太一样啊,这里直接把关闭文件的函数给放在了if条件里,被执行后也就是进行了一次关闭文件操作,和上面的一个关闭操作冲突了,因为标准IO的不能重复关闭
针对上面的错误情况,这里给出正确的情况:
if (EOF == fclose(Fd_1))
{
perror("fclose file failed:");
}
为了检验一下目前得到结论的正确性,我专门试了一下:
#include <stdio.h>
int main()
{
if (printf("高冷美丽善良小组长今天很开心:\t%d\n"))
{
printf("啊对对对,丁某觉得很对!\n");
}
return 0;
}

果然,在这里的判断条件确实被运行了一次。而且不仅仅如此,我们发现,这里的的printf函数也被认定成了true,这种情况我们在后续的也会遇到,比如if里面除了0之外的所有整数,即使是负数,他此时代表的也是true。
6、if 条件语句的实例
(1)、闰年
输入一个年份,判断他是否为闰年;如果不是则输出平年;
资料:能被4整除且不能被100整除的为闰年,世纪年能被400整除的是闰年
#include <stdio.h>
int main(void)
{
int a;
printf("请输入年份:\n");
scanf("%d",&a);
if (a % 4 == 0)
{
if(a % 100 != 0)
{
printf("该年份为闰年!");
}
else if(a % 400 == 0)
{
printf("该年份为闰年!");
}
else
{
printf("该年份为平年!");
}
}
else
{
printf("该年份是平年!");
}
return 0;
}
输入年月日,判断闰年平年后判断这是一年中的第几天
# include <stdio.h>
int main(void)
{
int a , b , c;
int d = 0;
printf("请输入年, 月, 日 :\n");
scanf("%d %d %d" , &a , &b , &c);
if(a % 100 != 0 && a % 4 == 0 || a % 400 == 0)
{
printf("该年份为闰年!\n");
d = 1;
}
else
{
printf("该年份是平年!\n");
}
if(b == 1)
{
}
else if(b == 2)
{
c = 31 + c;
}
else if(b == 3)
{
c = 31 + 28 + c;
}
else if(b == 4)
{
c = 31 + 28 + 31 + c;
}
else if(b == 5)
{
c = 31 + 28 + 31 + 30 + c;
}
else if(b == 6)
{
c = 31 + 28 + 31 + 30 + 31 + c;
}
else if(b == 7)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + c;
}
else if(b == 8)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + 31 + c;
}
else if(b == 9)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + c;
}
else if(b == 10)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + c;
}
else if(b == 11)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + c;
}
else if(b == 12)
{
c = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + c;
}
if(d = 1)
{
c = c + 1;
}
printf("这一天是 %d 的第 %d 天!\n" , a , c);
return 0;
}
(2)、三个数的最大值
输入3个整数,输出里面的最大值
// Input 3 integers
// Output the maximum value inside
#include <stdio.h>
int main(void)
{
int a , b , c , max ;
printf("Input 3 integers:\n");
scanf("%d %d %d", &a , &b , &c);
if (a > b)
{
max = a;
}
else
{
max = b;
}
if (max > c)
{
max = max;
}
else
{
max = c;
}
printf("Maximum values is : %d" , max);
return 0;
}
其实这个例子不用 if,直接用三目运算符更简单:
// Input 3 integers
// Output the maximum value inside
#include <stdio.h>
int main(void)
{
int a , b , c , max ;
printf("Input 3 integers:\n");
scanf("%d %d %d", &a , &b , &c);
max = a > b ? a : b ;
max = max > c ? max : c ;
printf("Maximum values is : %d" , max);
return 0;
}
且当数的个数更多的时候,用三目运算符肯定比直接if好,当然,太多了肯定就需要用循环来解决
// Input 10 integers
// Output the maximum value inside
#include <stdio.h>
int main(void)
{
int a , b , c , d , e , f , g , h , i , j , max ;
printf("Input 10 integers:\n");
scanf("%d %d %d %d %d %d %d %d %d %d", &a , &b , &c, &d , &e , &f , &g , &h , &i , &j);
max = a > b ? a : b ;
max = max > c ? max : c ;
max = max > d ? max : d ;
max = max > e ? max : e ;
max = max > f ? max : f ;
max = max > g ? max : g ;
max = max > h ? max : h ;
max = max > i ? max : i ;
max = max > j ? max : j ;
printf("Maximum values is : %d" , max);
return 0;
}
输入三个变量的值,使用if判断,交换变量中的值,把这三个数据从小到大进行排序,输出
#include <stdio.h>
int main(void)
{
// 笨方法
// 但引入中间量后又无法处置第二大的数
int a , b , c;
printf("请输入a、b、c的值:\n");
scanf("%d %d %d", &a , &b , &c);
if (a >= b && a >= c && b >= c)
printf("%d <= %d <= %d\n", c , b , a);
else if(a >= b && a >= c && c >= b)
{
c = c + b;
b = c - b;
c = c - b;
printf("%d <= %d <= %d\n", c , b , a);
}
else if(b >= a && b >= c && c >= a)
{
a = a + b;
b = a - b;
a = a - b;
c = c + b;
b = c - b;
c = c - b;
printf("%d <= %d <= %d\n", c , b , a);
}
else if(b >= a && b >= c && a >= c)
{
a = a + b;
b = a - b;
a = a - b;
printf("%d <= %d <= %d\n", c , b , a);
}
else if(c >= a && c >= b && a >= b)
{
a = a + c;
c = a - c;
a = a - c;
c = c + b;
b = c - b;
c = c - b;
printf("%d <= %d <= %d\n", c , b , a);
}
else if(c >= a && c >= b && b >= a)
{
a = a + c;
c = a - c;
a = a - c;
printf("%d <= %d <= %d\n", c , b , a);
}
return 0;
}
(3)、判断奇偶并进行简单计算
// 键盘输入两个非零整数A和B,
// 如果A和B都是偶数, 则输出两个数的和,
// 如果A和B都是奇数, 则输出两个数的差,
// 如果A是奇数B是偶数, 则输出两数积,
// 如果A是偶数B是奇数, 则输出A/B结果
# include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
printf("请分别输入两个非零正数 a 和 b:");
scanf("%d %d", &a, &b);
if(a%2 == 0 && b%2 ==0)
{
printf("%d\n", a+b);
}
if(a%2 != 0 && b%2 !=0)
{
printf("%d\n", a-b);
}
if(a%2 != 0 && b%2 ==0)
{
printf("%d\n", a*b);
}
if(a%2 == 0 && b%2 !=0)
{
printf("%d\n", a/b);
}
return 0;
}
二、switch 多分支条件语句
1、简单的switch
其使用大体上可以参照 if。不添加 break 的话,满足当前的条件也不会去退出,而是会顺序往下看,这一点利用好了的话也算是一种 “累加”
// 可以实现四则运算的一个简易计算器
#include <stdio.h>
int main(void)
{
int a, b;
char ch;
printf("请输入计算的式子:");
scanf("%d %c %d",&a,&ch,&b);
switch (ch)
{
case '+':
printf("%d + %d = %d\n", a, b, a + b);
break;
case '-':
printf("%d - %d = %d\n", a, b, a - b);
break;
case '/':
printf("%d / %d = %d\n", a, b, a / b);
break;
case '*':
printf("%d * %d = %d\n", a, b, a * b);
break;
default:
printf("暂不支持该种运算,请输入+ - * /\n");
break;
}
return 0;
}
default
在逻辑上,switch语句与多个 if 的语句有点像,都是属于并列关系,所以,那个default组块放在任意一个case块旁边都行
而那个default,跟else if语句中的最后一个else的逻辑也有点相似,都是除了上面被列出情况外的所有情况,也就是“兜底”了。
实际上,即使没有default,编译器也不会报错,因为,在条件都不满足的情况下,C语言自然结束。但这样,你就不知道自己输错了指令了
''
这对单引号,是对于单个字符的
表示你输入的,是char类型的字符
break
break出现在每个case组块的最后,用于执行条件后跳出switch。
我们知道,凡是满足其中一个case,这个switch语句就会结束,而结束的这个操作,就是break做到的,他可以打破一层循环或者镶嵌的束缚,
break为一个控制语句,后面记得加分号,同样的控制语句,还有continue,只不过continue是跳出本次循环,然后继续下次循环
switch与if同样作为条件语句,很多情况下其实是可以转换的,但有些switch的写法,if却不能直接套,就比如switch程序里面带有...
// Outputting scores and assigning grades to them?
#include <stdio.h>
int main(void)
{
int a;
printf("score:\n");
scanf("%d",&a);
switch (a)
{
case 90 ... 100:
printf("Your scores : A");
break;
case 80 ... 89:
printf("Your scores : B");
break;
case 70 ... 79:
printf("Your scores : C");
break;
case 60 ... 69:
printf("Your scores : D");
break;
case 0 ... 59:
printf("Your scores : E");
break;
default:
printf("Input error!");
break;
}
return 0;
}
case 90 ... 100:这句话中的 90 ... 100 代表:90 ,91 , 92 , 93 , 94 , 95 , 96 , 97 , 98 , 99 , 100,即 90 和 100,以及二者中间的数都被包括进去了
2、switch语句的实例
(1)、闰年
// 输入年月日,判断闰年和平年
// 并判断他是一年中的第几天
# include <stdio.h>
int main(void)
{
int a , b , c;
int d;
printf("请输入年,月,日 :\n");
scanf("%d %d %d" , &a , &b , &c);
if(a % 100 != 0 && a % 4 == 0 || a % 400 == 0)
{
printf("该年份为闰年!\n");
d = 1;
}
else
{
printf("该年份是平年!\n");
}
switch (b)
{
case 12:
c = c + 30;
case 11:
c = c + 31;
case 10:
c = c + 30;
case 9:
c = c + 31;
case 8:
c = c + 31;
case 7:
c = c + 30;
case 6:
c = c + 31;
case 5:
c = c + 30;
case 4:
c = c + 31;
case 3:
c = c + 28;
case 2:
c = c + 31;
case 1:
default:
break;
}
if(d = 1)
{
c = c + 1;
}
printf("这一天是 %d 的第 %d 天!\n" , a , c);
return 0;
}
三、while循环
1、while

如上图,我们在上文if的部分中遇到了一种情况,若是输入的数字更多,此时对其进行排序,若是采用原来的办法,工作量是巨大的,所以我们打算采用循环的方式来应对,即把重复性的工作扔给了计算机,对于计算机来说,这种重复工作却是他最擅长的工作,效率很高。
while后面的括号中跟的是一个表达式,即一个表示判断,准确来说跟if哪里一样指的是0或者1,表达式为真则继续循环,直至为假
而要写出一个循环,则需要遵守他的三要素:
- 循环变量的初值,
- 循环退出条件,
- 循环控制变量的递增递减
// Printable multiplication table.
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 9)
{
int j = 1;
while (j <= i)
{
printf("%d * %d = %d\t", i , j , i * j);
j++;
}
printf("\n");
i++;
}
return 0;
}

2、do while循环
// Guessing game:
// Enter an integer,
// end when you get the answer right,
// or keep guessing.
//
// The answer is 8
#include <stdio.h>
int main(void)
{
int i = 0;
printf("Enter an integer:\n");
do
{
scanf("%d", &i);
if (i == 8)
{
printf("True!\n");
break;
}
else
{
printf("False!\tEnter again:\n");
}
} while (i != 8);
// while 中的i == 8只是决定你能不能进入下一次循环,
// 即执行1次后可否能够继续第二次,在本题中也就是第一次就猜对的情况,
// 若是没猜对,也就是while的判断为真,就继续下次循环
return 0;
}
容易想得到,这个实例的逻辑还适用于 “无限制次数密码登陆”
3、while死循环
这种循环常被用来计数,在单片机中运用的比较多。
// ms级延时
void delay_ms(uint32_t n)
{
while(n--)
{
SysTick->CTRL = 0;
SysTick->LOAD = 168000-1; // 1ms的计数值
SysTick->VAL = 0;
SysTick->CTRL = 5;
while((SysTick->CTRL & 0x10000) == 0);
}
SysTick->CTRL = 0;
}
我们运用这种死循环的时候跟if括号中的有一定的相似之处,即只存在真与假之分,但这里我们一般用的是数字,而不是条件,对于数字来说,只有0为假,其他数字包括负数都为真。
四、for循环
相比于while循环,for循环更加直接,因为他在括号里直接把三要素给列出来了,中间用分号隔开,在大括号里,就是需要执行的操作了。
1、for循环的使用
for循环的一般格式:
for (初始化表达式; 循环条件; 更新表达式)
{
// 循环体代码块
}
在这个格式中,每个部分的含义如下:
- 初始化表达式:用于初始化循环变量,一般是赋初值给循环变量。
- 循环条件:指定循环执行的条件,只有当条件为真时,循环体会被执行。如果条件为假,则循环终止。
- 更新表达式:用于更新循环变量的值,一般是对循环变量进行增量或减量操作。
下面是一个示例,展示了一个计算1到5之间整数和的for循环:
#include <stdio.h>
int main() {
int sum = 0;
int i;
for (i = 1; i <= 5; i++) { // 初始化表达式为i=1,循环条件为i<=5,更新表达式为i的自增操作
sum += i; // 循环体代码块,将i累加到sum中
}
printf("Sum: %d\n", sum); // 输出结果为Sum: 15
return 0;
}

在这个示例中,初始化表达式将变量i设置为1,循环条件判断i是否小于等于5,如果满足条件,则执行循环体代码块,并将i累加到sum中。在每次循环结束后,更新表达式将i自增1。当i的值达到6时,循环条件为假,循环终止。最后,使用printf函数打印出sum的值,即1到5之间整数的和。
2、for循环死循环
对于for循环而言,也存在着死循环的情况。死循环发生的条件是控制变量的更新永远不能使循环条件为假,从而使循环条件永远为真。
例如:
for(a=1;a>0;):在这种情况下,控制变量a不会被更新,因此a永远大于0,循环条件永远为真。for(a=0; ;a++):在这种情况下,没有循环条件,也就意味着没有退出条件,循环会一直进行下去。for( ; ; ):在这种情况下,三个条件式默认都为真,从而形成死循环。
由此也可以看出,for循环的3条语句不是必填的,但不填有不填的后果:
- 初始化不填:控制变量的初始值只能在循环之前赋值了
- 循环条件不填:没有循环条件默认为真,就是死循环
- 循环更新语句不填:控制变量不更新,循环条件的结果永远不变,也会死循环
另外,要打破死循环的话,用break
3、省略大括号的情况
是的,对于if、while和for等控制流语句,当大括号中的内容只有1行时,可以省略大括号。
不过,这样做可能会导致代码可读性降低,增加出错的可能性。建议在编写代码时保持良好的编码风格,始终使用大括号来明确表示代码块的范围,即使代码块只有1行。这样可以提高代码的可读性和可维护性,并减少潜在的错误。以下是一个示例:
if (condition)
statement; // 只有1行,可以省略大括号,但不推荐
while (condition)
statement; // 只有1行,可以省略大括号,但不推荐
for (i = 0; i < n; i++)
statement; // 只有1行,可以省略大括号,但不推荐
更好的做法是始终使用大括号,即使代码块只有1行:
if (condition) {
statement;
}
while (condition) {
statement;
}
for (i = 0; i < n; i++) {
statement;
}
这种方式可以提高代码的可读性,使代码结构更清晰,减少潜在的错误。同时,如果需要在代码块中添加更多语句,也可以避免忘记添加大括号而引发错误。
话虽然是这样说,但实际中我们省略这个大括号的情况非常常见,而且我个人甚至觉得,省略了这个大括号后,某种程度上代码的可读性其实增强了。
五、goto循环
1、介绍
可以理解为在一个在一条直线上无限运行的飞雷神。就是说,在当前位置做一个标记1,在程序当前位置之前的某个位置做一个标记2,然后goto(飞雷神),从当前的位置(标记1)回到标记2,然后从标记2运行,然后运行到刚刚的位置(标记1),飞雷神again……这两个标记一直存在,所以从
标记1-> <-标记2的过程一直持续
goto 是一个在编程中使用的关键字,用于无条件地跳转到代码中的标记位置。它可以让程序直接跳转到代码的指定位置,绕过正常的程序流程。
goto的格式:
label:
需要重复执行的部分
goto label;
label是标记名,叫啥都行,第一个label后面跟的是一个冒号。
#include <stdio.h>
int main() {
int i = 1;
start: // 定义一个标记 "start"
printf("i: %d\t", i);
if (i <= 5)
{
printf("%d \n", i);
i++;
goto start; // 无条件跳转到 "start" 标记位置
}
printf("\n");
return 0;
}

2、goto用于页面的返回
我们在做项目的时候,很多时候会遇到一种情况:不断点击弹出窗口的某个选项,最后却想回到最初的位置,要想做到这一点,我们往往会通过整体的设计,让这一系列操作在一个大的循环里面,大循环套中循环,中循环套小循环,多次break来返回指定的窗口页面。
这种情况并不少见,虽然goto很危险,但用在这种情况下是再好不过了的。
int main(int argc, char const *argv[])
{
int x, y;
Init_Dev(); // 初始化_1
Init_Font(); //初始化字库
// 选择"load/specification"
int flag_lo_sp; // 此参数用于从specification(说明书)内容页面切换到 "load/specification"页面
dingwei_1: // 定义goto的标签1
flag_lo_sp = 0;
// "load/specification"页面
SHOW_BMP_zhengchang("face_2.bmp");
char *str = "登录";
Display_characterX(50,120,str,0x00ff0000,7); //显示字符串,红色字体
char *arr = "说明书";
char *arr_1 = "左上:删除当前图片";
char *arr_2 = "右上:退出程序";
char *arr_3 = "左下:缩小图片";
char *arr_4 = "右下:放大图片";
Display_characterX(415,120,arr,0x0000ff00,7); // 显示字符串,绿色文字
Get_Xy(&x, &y); // 触摸屏事件
if (x >= 0 && x <= 400 && y>=0 && y<=480)
{
FUN_LOAD();
}
else if (x > 400 && x <= 800 && y>=0 && y<=480)
{
flag_lo_sp = 1;
SHOW_BMP_zhengchang("face_2.bmp");
Display_characterX(240,120,arr_1,0x000000ff,3);
Display_characterX(240,180,arr_2,0x000000ff,3);
Display_characterX(240,240,arr_3,0x000000ff,3);
Display_characterX(240,300,arr_4,0x000000ff,3);
}
// 如果处于说明书内容页面,点击屏幕任意位置会返回到"load/specification"页面
if (1 == flag_lo_sp)
{
Get_Xy(&x, &y); // 触摸屏事件
if (x >= 0 && x <= 800 && y>=0 && y<=480)
goto dingwei_1;
}
……(其他部分的代码)
……
……
}
这是第一阶段大项目里主函数的一部分,下面给一下相关的运行效果:

3、破开goto的方法
首先还是要声明:goto 语句本身并不是死循环,它是一种控制流语句,用于无条件地跳转到指定的标记位置。虽然在某些情况下 goto 可能被用于实现循环或跳出循环的效果,但这并不意味着 goto 本质上是死循环。
还要注意,goto 语句的使用应该谨慎,并尽量避免滥用。使用结构化的控制流语句来组织代码是更好的选择,而 if 语句和 break 语句是常见的控制流工具,可根据实际需求进行使用。
我们通常采用的办法,是利用 “if + 标志位” 的办法。
这种破开条件,一般需要提前设出一个标志位(变量),一般用flag,然后就在关键的语句后面对flag进行变化,最后设出if,当flag满足自己if里面给出的条件的时候就破开,理解和使用起来都不算麻烦,
上面的
实例_1就是用的这种方法
#include <stdio.h>
int main()
{
int i = 0;
int flag = 0; // 标志位初始化为 0
start:
i++;
if (1 == flag)
{
goto end; // 当标志位为 1 时,跳转到 "end" 标记的位置
}
if (i < 5)
{
printf("%d ", i);
if (3 == i)
{
flag = 1; // 当 i 等于 3 时,将标志位设为 1
}
goto start; // 继续循环
}
end:
printf("\n");
printf("Loop ended.\n");
printf("i: %d\n", i);
printf("flag: %d\n", flag);
return 0;
}

不能使用 break 语句来直接破解 goto 语句的循环。break 语句用于终止循环结构(例如 for、while 或 do-while 循环),而不是跳出 goto 标记。
goto 语句是无条件地跳转到指定标记位置的控制流语句,而 break 语句用于在循环结构中提前退出循环。它们具有不同的作用和语义。
如果你使用 goto 语句创建了一个带有标记的循环,并且想要在循环内部的某个地方终止循环,你应该使用 goto 语句跳转到循环外部的标记位置,而不是尝试使用 break 语句。
六、综合实例
1、计算交错数列

// 编程计算交错序列 1-2/3+3/5-4/7+5/9-6/11...的前N项之和;
// (哥们,看题目的时候注意优先级)
// 要求结果保留3位小数
# include <stdio.h>
int main(void)
{
float sum = 0;
int n = 0, i = 0;
float j = 0;
printf("What is the number of terms you want the sum of?\n");
scanf("%d", &n);
for(int i = 1 ; i <= n ; i++)
{
if((i + 2) % 2 != 0) // if-else 实现正负 1 的交迭
{
j = 1 / (i-0.5);
j =j * 0.25;
j = j + 0.5;
// 化简部分,
// 最后化简的结果不要是分子分母同时含有 i 的,不然列出来会报错
// 其实这里1/(i-0.5)*0.25+0.25化简一下实际上就等于i/(2i-1)
sum = sum + j; // 呼应 if 小括号里的内容
}
else
{
j = 1 / (i-0.5);
j =j * 0.25;
j = j + 0.5;
sum = sum - j;
}
}
printf("The sum of the first %d terms is %.3f\n", n, sum);
// 需要注意的一点就是这个打印格式的选择了,
// 那个点十分容易忽略
return 0;
}

2、四选三并进行互不相同且无重复的排列
// 有1、2、3、4个数字,
// 能组成多少个互不相同且无重复数字的三位数?
// 都是多少?
# include <stdio.h>
int main(void)
{
int i, j, k; // 个位,十位,百位
for(int i = 1 ; i <= 4 ; i++)
{
// 每个位数上都有 4 种可能,但是其中存在重复的情况
for(int j = 1 ; j <= 4 ; j++)
{
for(int k = 1 ; k <= 4 ; k++)
{
if(i != j && j != k && i != k) // 去重复
{
printf("%d%d%d\t", i, j, k);
}
}
}
printf("\n");
}
return 0;
}

3、水仙花数
// 求三位数的水仙花数
// 个位数的立方 加上 十位数立方 加上 百位数立方 等于原本的这个数 就叫水仙花数
# include <stdio.h>
int main(void)
{
int i = 100;
int j, k, l;
// 个十百三个值不能定义在外面,不然就变成了一个确定的值了
for(i = 100; i <= 999; i++)
{
j = i % 10; // 个位
k = i % 100 / 10; // 十位
l = i / 100; // 百位
if (i == (j*j*j + k*k*k + l*l*l)) // 不能用 ^, 不然识别不出来
{
printf("%d\n", i);
}
}
return 0;
}

4、由 * 组成的图形
(1)、等腰三角形
// 打印出由 * 组成的三角形,如下:
// *
// ***
// *****
// *******
// *********
# include <stdio.h>
int main(void)
{
int i = 1;
int num, j, k, l;
printf("num: ");
scanf("%d", &num);
for(; i <= num; i++) // 行数列,每一行空格与*共存,可以分别(分先后)写出
{
for(j = 1; j <= num-i; j++) // 只需要左半部分的空格就可以定位了
{
// (num-i) 是左半部分空格的每一行的数目
printf(" ");
}
for(l = 1; l <= 2*i-1; l++)
{
// (2*num-1) 是每一行的 * 数量
printf("*");
}
printf("\n"); // 区分开每一行之间的内容
}
return 0;
}

(2)、直角三角形

形状 1:
// 打印出由 * 组成的直角三角形
# include <stdio.h>
int main(void)
{
int i, j; // 用于循环
int num; // 层数
printf("num: ");
scanf("%d", &num);
for(i = 1; i <= num; i++) // 行数
{
for (j = 1; j <= 2*i-1; j++) // 画*图案
{
// 2*i-1 为每一行的 * 数目
printf("*");
}
printf("\n"); // 必须加在两个for之间,目的是断开每一行的*
}
return 0;
}

形状 2:
// 由等腰三角形的经验,形状2需要先打空格来定位
# include <stdio.h>
int main(void)
{
int i, j, k; // 用于循环
int num; // 层数
printf("num: ");
scanf("%d", &num);
for(i = 1; i <= num; i++) // 行数
{
for (k = 1; k <= 2*(num-i); k++) //画空格
{
// 2*(num-i) 为每一行空格的数目
printf(" ");
}
for (j = 1; j <= 2*i-1; j++) // 画*图案
{
// 2*i-1 为每一行的 * 数目
printf("*");
}
printf("\n"); // 区分开每一行之间的内容
}
return 0;
}

形状 3:
// 形状3只需要更换形状1中空格与*模块的要求
// 然后补上*模块即可
# include <stdio.h>
int main(void)
{
int i, j, k; // 用于循环
int num; // 层数
printf("num: ");
scanf("%d", &num);
for(i = 1; i <= num; i++) // 行数
{
for (j = 1; j <= 2*i-2; j++) // 画空格
{
// 2*i-2 为每一行的空格数目
printf(" ");
}
for (k = 1; k <= 2*(num-i)-1 ; k++)
{
// 2*(num-i)-1 为每一行的*数目
printf("*");
}
printf("\n"); // 区分开每一行之间的内容
}
return 0;
}

形状 4:
# include <stdio.h>
int main(void)
{
int i, j; // 用于循环
int num; // 层数
printf("num: ");
scanf("%d", &num);
for(i = 1; i <= num; i++) // 行数
{
for (j = 1; j <= 2*(num-i)-1 ; j++)
{
// 2*(num-i)-1 为每一行的*数目
printf("*");
}
printf("\n"); // 区分开每一行之间的内容
}
return 0;
}

(3)、菱形
# include <stdio.h>
int main(void)
{
int i, j, k, l;
int num;
printf("num: ");
scanf("%d", &num);
for (i = 1; i <= num/2+1; i++) // 上半部分的行数
{
for (j = 1; j <= num/2+1-i; j++) // 上半部分的左小部分空格,先写来定位
{
// num/2+1-i 为每行空格行数
printf(" ");
}
for (k = 1; k <= 2*i-1; k++) // 上半部分的*部分
{
// 2*i-1 为每行*内容
printf("*");
}
printf("\n");
}
j = k = 0;
for (l = 1; l <= num/2; l++) // 下半部分的行数
{
for (j = 1; j <= l; j++) // 下半部分空格区
{
// l 为下半部分左边的每行空格个数
printf(" ");
}
for (k = 1; k <= (num/2-l+1)*2-1; k++) // 下半部分*区
{
// (num/2-l+1)*2-1 为下半部分每行*的个数
printf("*");
}
printf("\n"); // 区分开每一行之间的内容
}
return 0;
}

(4)、变种字母类
// A
// ABA
// ABCBA
// ABCDCBA
// 去找了下参考代码,还没看完,大致思路就清楚了
// 原来继续套娃即可,多分一个模块的事情,
// 原本我不想往那个方面想的,因为模块堆积繁杂而无聊
// 但是单独写出一行行回文字符的难度太大,实现有点困难
// 也只好继续写模块了
# include <stdio.h>
int main(void)
{
int i, num, j, k, l;
char words[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
printf("Number of layers to output (less than or equal to 26):");
scanf("%d", &num);
for (i = 1; i <= num; i++) // 行(层)数
{
for (j = 1; j <= num-i; j++) // 左边的定位空格
{
printf(" ");
}
for (k = 0; k < i; k++) // 左边占了一大半的顺序字符
{
printf("%c", words[k]);
}
for (l = i-1; l >= 0; l--) // 右边一小半的逆序字符
{
printf("%c", words[l-1]);
// 这里要注意到右边的小一些,所以要 l-1,
// 是 l 就一样大了
}
printf("\n"); // 分行
}
return 0;
}

写完这个,那么写之前见到的异形排列的乘法表也有思路了,但也没必要去写了
七、for 和 while 的区别
1、while中的递增递减是可以中途停下的
while循环中放一个if-else,把递增递减语句放在else里面,然后用if来控制递增递减停止和停止后干什么,if满足后会再次循环一遍才继续开始递增递减。
这种情况在普通情况下不算啥事,因为i可以随时减,只需要在大括号中加一个条件if触发即可,但是在单向链表中就很要命,因为此时只能单向操作,这时候就必须用到while而不是for了
/*for (POS->next; POS->next != NULL; POS=POS->next)
{
printf("插眼2:\n");
printf("此时的TMP->next:%d\n", TMP->next->date);
printf("此时的POS->next:%d\n", POS->next->date);
if (TMP->next->date == POS->next->date)
{
flag = 1;
A = POS->next; // 用A来保存要删数据的地址,地址是不会变的,等会直接把A给free掉就好了,这样就不会混淆指向了
POS->next= A->next;
A = NULL;
free(A);
printf("插眼3:\n");
//POS->next = POS;
}
此处用for循环有些问题,因为for里面完成一次后TMP必然往后面遍历,
但这里需要控制他停下来再次比较一次,这里做不到,
故而会导致程序出问题
}*/
while (POS->next != NULL)
{
if (TMP->next->date == POS->next->date)
{
flag = 1;
A = POS->next; // 用A来保存要删数据的地址,地址是不会变得,等会直接把A给free掉就好了,这样就不会混淆指向了
POS->next= A->next;
A = NULL;
free(A);
}
else
{
POS=POS->next;
}
}
2、while(n--)计数的坑
while(n--)这个被用的挺广泛的,但是我现阶段还没咋用,于是现在才发现其中的坑:
#include "head.h"
int main()
{
int n;
printf("请输入你要输出的个数:\t");
scanf("%d", &n);
while (n--)
{
printf("n:\t%d\n", n);
}
return 0;
}

看得出来,while(n--)循环体中执行的第一个是从n-1开始的;
再看这个斐波拉切数列:
#include "head.h"
int FUN(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
else
{
return FUN(n-1)+FUN(n-2);
}
}
int main()
{
int n, b;
printf("请输入你要输出的个数:\t");
scanf("%d", &n);
// for (int i = n; i>0; i--)
// {
// b = FUN(i);
// printf("%d\n", b);
// }
while (n--) // 之前还没有注意到这种while(n--)第一次开始执行的是n-1的,所以在循环中要改变一下n
{
b = FUN(n+1);
printf("%d\n", b);
}
return 0;
}
由于上面介绍的这个坑,
这里的b = FUN(n);被迫只能写成b = FUN(n+1);

浙公网安备 33010602011771号