目录
2.break和continue在do while循环中的应用
在生活中我们会面临各种选择,它们代表着一个个分支,在选择做出的那一刻,我们便走上了那条分支,c语言中引入了两种语法用来描述分支。先来看看第一种语法。
if语句
1.单分支结构
if (表达式1)
{
语句;
}
if (表达式2)
{
语句;
}
像这样的if语句还能往下写很多个,程序会依次判断两个表达式的真假,并根据判断结果执行语句。而在单分支结构中,第一个if表达式的判断结果不会影响第二个if表达式。
2.双分支结构
if (表达式1)
{
语句;
}
else (表达式2)
{
语句;
}
与单分支结构不同,这种格式的if与else是互斥的,也就是说,第一个if的表达式成立,程序只会执行if的语句,而不会执行else的语句。if与else是一种非此即彼的关系。
3.多分支结构
if (表达式1)
{
语句;
}
else if (表达式2)
{
语句;
}
else (表达式3)
{
语句;
}
那么在这种格式下,程序会依次对三个表达式进行判断(当然可能还有更多的表达式),如果一个表达式成立,执行该表达式下的语句,不对其他表达式判断。(就是如果if的表达式为真,程序执行if下的语句,跳过else if与else代码块)
4.常见编程陷阱
4.1赋值符的区别
思考一个问题,c语言中的‘=’是否与数学中的‘=’意义相同?
再来看看下面两个代码
int i = 0;
if (i = 0)//表达式1
{
printf("%d", i);
}
if (i == 0)//表达式2
{
printf("%d", i);
}
第一个代码什么都不输出,第二个代码输出0。这是因为在c语言中‘=’是赋值符,‘==’用来判断两个数是否相等。程序在判断表达式1时,将0赋值给i,这使得表达式的结果为假,所以第一个if连语句都没执行。而判断两数是否相等经常出现在if语句的表达式中,‘=’与‘==’的区别要时刻注意。
4.2悬空else
int main()
{
int a = 2;
int b = 3;
if (a == 3)
if (b == 2)
printf("hello world");
else
printf("hello bit");
return 0;
}
这串代码将会输出什么? hello bit?其实什么都不会输出。因为else与最近的if语句匹配。
并且这串代码连大括号也没加,有质量的代码风格应该像下面这样。
int main()
{
int a = 2;
int b = 3;
if (a == 3)
{
if (b == 2)
{
printf("hello world");
}
else
{
printf("hello bit");
}
}
return 0;
}
这样写代码是不是可读性更高了?所以在敲代码时要非常注意这些细节,从而增加代码的可读性。
switch语句
1.语法结构
switch与if一样是分支语句。switch多用与多分支情况。例如输入1~7,输出星期一到星期天。
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;
}
return 0;
}
下面来看看switch的语法结构
switch (整形表达式)
{
case:整形常量表达式
语句;
}
switch后面的整形表达式可以是一个变量,就像刚刚例子中的day,注意变量的值必须为整形。而case后要跟整形常量表达式,所以day这样的变量不能跟在case后面,但可以跟1,1 + 2,1 * 2...总之表达式算出来要是一个整形。
2.break在switch中的应用
不知道你们注意到没有,我在每条case语句最后加了break,如果没有这个break会有什么发生?
想输出星期一时却输出了星期一到星期天... 其实程序在执行完case 1的语句后,会依次执行后面其他case的语句,想要只输出星期一,就需要在case最后加上一个break,使程序跳出整个switch语句。
3.default在switch中的应用
如果在输入时输错了值,程序是什么都不会执行的。要想让输入者知道自己输错了,我们可以在最后加上default条件。
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;
dafault:
printf("输入错误,请重新输入\n");
break;
}
return 0;
}
如果输入除了1~7以外的其他整形,程序就会执行default后的语句。(这里最好在default后也加上一个break,养成好的代码风格)
最后,如果我们想输出的结果只有工作日或周末,我们就能巧妙地用break来实现。
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;
dafault:
printf("输入错误,请重新输入\n");
break;
}
return 0;
}
分支语句的讲解就到这啦,下面我们开始讲解循环。
我们在生活中做出选择后,可能会不断地做一些事,不断地重复以实现我们的目标,达到心中对自己的期望。在c语言中引入了三种语法,这些语法就能让程序重复地做一些事。
while循环
1.基本语法
while(表达式)
{
语句;
}
表达式为真,while循环开始,执行语句,为假则不执行语句。而这个表达式可以看作条件判断部分,是对循环的一种限制。要实现循环,我们还要有循环变量和调整部分。
int main()
{
int i = 1; // 我们不妨把i叫做循环变量
while (i <= 10)// 我们把"i <= 10"叫做条件判断部分
{
printf("%d ", i);
i++; // 这就是调整部分啦
}
return 0;
}
怎么让程序输出1~10的数?首先我们要对循环变量初始化,这是循环的开始。接着我们要确定条件判断部分,这决定了循环的结束。当循环变量不满足该部分的条件时,循环跳出,也就是结束啦。为什么循环变量会不满足判断部分的条件?其实在循环中还有一个调整部分,这个调整使循环变量逐渐增大,最终循环变量会不满足判断部分的条件,所以上面的程序在打印完10后就停止了。
总而言之,一个循环要有三个部分:循环变量的初始化部分,条件判断部分,调整部分。
2.break在while循环中的应用
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i++;
if (i == 5)
break;
}
return 0;
}
这串代码的结果是什么?答案是输出1~4。break在while循环中的作用是跳出整个循环,也就是使循环停止。当 i 的值为4时,下一步程序打印4 ,接着 i++ 使i的值变成5,满足if的表达式,程序执行break,循环也就结束了。
3.continue在while循环中的应用
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
return 0;
}
再看看这串代码,它的结果又是什么?答案是1 2 3 4 然后程序死循环。这也就是说continue不会使整个循环结束,它只会跳出一次循环,也可以理解成跳过continue后面的代码。当i为4时,程序打印4,i++ 后 i 为5,满足 if 的条件,程序执行continue,跳过printf与i++再循环,而i的值没变,i 再次满足if的条件,continue又跳过printf和i++...程序就这样子跑死了。所以我们在写continue时要注意不要把调整部分写在它的后面,跳过调整部分会使代码死循环的。
总之我们明白continue的作用是跳过后面的代码,再进行循环。
如果我们写了很多的代码,使得循环变量,条件判断部分和调整部分之间的距离太远,以至于我们很难分清谁是谁啦,这时候 for循环就能解决这个痛点。
for循环
1.基本语法
for (表达式1;表达式2;表达式3)
{
循环语句;
}
表达式1就是循环变量的初始化部分,表达式2是条件判断部分,表达式3是调整部分。for循环将循环的三个部分放在一行,这使我们修改循环体变得容易。
在首次进入for循环时,程序的执行过程是:表达式1 ->表达式2 -> 循环语句 -> 表达式3。也就是说,程序在第一次循环时先初始化变量,接着判断变量是否满足判断部分的条件,然后执行循环语句,最后进行变量的调整。
画图理解就是这样的,看着有点点丑...第二次以后的循环是这样的。
就像一个逆时针的圈,循环在不断地转。
2.break与continue在for循环中的应用
这两个关键词的作用和while循环一样,唯一不一样的是,continue不会造成for的死循环。
这是因为调整部分不在循环语句中,for循环中的continue不会跳过 i++,所以程序会跳过5打印1~10。
3.特殊情况
1)在for循环中,三个循环的条件可以省略。
int main()
{
for (;;)
{
printf("hehe\n");
}
return 0;
}
而如果条件判断部分被省略,这意味着判断恒为真。此时屏幕上会不断的打印”hehe“。(这种情况只是了解一下,初学者最好不要这样写代码,容易导致很多问题)
2)可以用两个变量控制for循环
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hehe\n");
}
return 0; }
这时只会打印两个”hehe“。
3)省略初始化变量部分
int i = 0;
int j = 0;
for(i=0; i<10; i++)
{
for(j=0; j<10; j++)
{
printf("hehe\n");
}
} //程序打印几个"hehe"?
很简单,9个。那下面这串代码呢?
int i = 0;
int j = 0;
for(; i<3; i++)
{
for(; j<3; j++)
{
printf("hehe\n");
}
}
9个还是3个?还是什么都没有?(建议把代码复制到IDE,自己调试感受程序的运行)
答案是3个。i 为0时,j 从0增加到2,循环了三次。当 i 为1时,j 不再是0,而是3,因为我们没有重新把 j 赋值成0。所以 i 为1,2的循环中,j 不满足循环的判断条件,程序不执行打印。
do while循环
1.基本语法
do
{
循环语句;
} while (表达式);
注意while那一行最后有一个' ; ' 。
在了解其他两种循环后,do while循环的语法可以说是一看就明白啦。这里说下do while循环的特点,和while循环很相似,唯一不同的是无论怎样,程序会先执行一遍循环语句,再进行条件的判断。所以说程序至少会执行一次。
2.break和continue在do while循环中的应用
break和continue在do while循环中的作用和while循环一样,这里不再赘述。由于使用场景有限,do while循环很少使用。
应用练习
1.计算n的阶乘
要计算n的阶乘,首先要用循环产生1~n之间的数,让这些数相乘。所以我们创建一个变量并赋值为1,每产生一个数就乘上这个变量,最后打印这个数。接下来是代码的实现。
//计算n的阶乘
int main()
{
int i = 0;
int ret = 1;
int n = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
ret = ret * i;//也能写成ret *= i;
}
printf("%d", ret);
return 0;
}
2.计算 1!+2!+3!+……+10!
刚刚写的代码能够计算n的阶乘,现在要把阶乘相加。我们只需要在for循环的外层在套一个for循环,假设外层的循环变量是i,i为1时,让内层的循环能计算1的阶乘,i为2时,让内层的循环计算2的阶乘...这样下去我们的代码就能实现了。
int main()
{
int i = 0;
int n = 0;
int k = 0;
int ret = 1;
int sum = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
for (k = 1; k <= i; k++)
{
ret *= k;
}
sum += ret;
ret = 1;//这行代码别忘啦
}
printf("%d", sum);
return 0;
}
陷阱: 在计算出n的阶乘ret,并把ret的值加给sum后,我们需要把ret的值重新赋为1。假设我们没有重新赋值的操作,ret计算的结果便不再是n的阶乘了。
可这个算法的效率不够高,我们能再优化这串代码。假设我们要算1!+ 2!+3!,假设3!时,内层的for循环反复计算了2!,如果求和的个数比较多,是不是重复了很多次相同计算?其实我们只要在计算完一个数的阶乘后,把这个值加给另一个变量。上代码
int main()
{
int i = 0;
int n = 0;
int sum = 0;
int ret = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
ret = ret * i;
sum += ret;
}
printf("%d", sum);
return 0;
}
有没有注意到我只是在计算n的阶乘的程序中加上两行代码。
3.在有序数组中查找某个数字(二分查找)
假设随机给出一个1~100的数,让你猜这个数,第一次我们都会猜中间数50,然后让对方说猜大了还是猜小了,之后还是说中间数...二分查找也是这个道理,我们先输入一个数 k,让程序判断数组的中间元素与n的大小,如果中间元素更小,我们下次只需要对中间元素右边的数组进行相同的操作,然后让程序不断地重复,直到中间元素等于n,我们退出程序,并且打印这个元素在数组中的下标。
int main()
{
int k = 0;
scanf("%d", &k);
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int right = sizeof(arr) / sizeof(arr[1]) - 1;
//数组下标从0开始
//计算出数组元素个数后我们还要减一
while (left <= right)
{
int mid = 0;
mid = (right + left) / 2;
if (arr[mid] > k)
{
right = mid - 1;
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
printf("找到了,下标是%d", mid);
break;
}
}
if (left > right)
printf("找不到");
return 0;
}
最后,这篇博文是对C语言学习的阶段性总结,文章内容相当的基础,虽然不多,但是写完它还是花了一个下午时间,如果有错误,欢迎指正。