1.什么是语句
C语句可分为以下五类:
-
表达式语句
-
函数调用语句
-
控制语句
-
复合语句
-
空语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句。
可分成以下三类:
-
条件判断语句也叫分支语句:if语句、switch语句;
-
循环执行语句:do while语句、while语句、for语句;
-
转向语句:break语句、goto语句、continue语句、return语句。
2. 分支语句(选择结构)
C语言选择结构也称分支结构,是一种根据判断条件的成立与否来确定程序执行方向的一种程序设计结构。其中,判断条件中会涉及到关系运算符和逻辑运算符。
2.1 C语言关系运算符及其用法
关系运算实际上就是比较运算,类似于数学当中比较数字大小的运算。C语言提供了 6 种关系运算符(relational operator),如下表所示。
关系运算符 | 描述 | 示例(关系表达式) |
---|---|---|
== | 等于 | a+b == c |
> | 大于 | a+10 > c |
< | 小于 | b < a+10 |
>= | 大于等于 | c >= b |
<= | 小于等于 | a <= c |
!= | 不等于 | a != b |
关系运算符的左右两边可以是变量、数值或算术表达式,用关系运算符连接而成的表达式称为关系表达式。在含有算术运算符的关系表达式中,算术运算符的优先级高于关系运算符。
关系表达式的运算结果是一个逻辑值:“真”或“假”,在 C语言中用数值 1 表示“真”,用数值 0 表示“假”。因而,每当 C语言对关系表达式进行运算时,总是产生结果数值 1 或 0。下面的语句把 1 赋值给变量 a,把 0 赋值给变量 b:
a = (8<10); //(8<10)为“真”,其结果值为 1,因而变量 a 被赋值 1
b = (3==4); //(3==4)为“假”,其结果值为 0,因而变量 b 被赋值 0
下图展示了用不同的算法描述方法对选择结构程序设计流程进行算法描述。
2.2 C语言逻辑运算符及其用法
关系运算符只是测试左右两个值之间的关系(把它们相互比较),逻辑运算符(logical operator)则是把多个关系表达式组合起来,判断最终的结果是“真”还是“假”。因而,有时候逻辑运算符又称为复合关系运算符(compound relation operator)。C语言提供了 3 种逻辑运算符,如下表 所示。
运算符 | 含义 | 说明 | 示例 |
---|---|---|---|
&& | 逻辑与 | 运算符两边的表达式都成立(真),返回 1;只要有一个不成立(假),返回 0 | (23)&&(33) 的值为 0 (2<3)&&(3==3) 的值为 1 |
|| | 逻辑或 | 运算符两边的表达式只要有一个成立,返回 1;只有两边的表达式都不成立时,返回 0 | (23)||(33) 的值为 1 (2<1)||(2==3) 的值为 0 |
! | 逻辑非 | 运算符后边的表达式成立(真),返回 0,否则返回 1 | !(2==3) 的值为 1 !(2<3) 的值为 0 |
对于逻辑运算符优先级的问题,逻辑非!
的优先级最高,不仅优先于关系运算符,甚至优先于算术运算符,其次是逻辑与&&
,逻辑或||
优先级最低,而逻辑与&&
和逻辑或||
的优先级低于关系运算符。当一个判断条件表达式中同时出现关系运算符、逻辑运算符、算术运算符时,其运算优先关系如下:
( ) → 函数、! → *、/、% → +、- → <、>、!=、<=、>= → &&、||
2.3 C语言if else语句的用法
条件语句就是根据判断条件的成立与否(“真”或“假”),来决定接下来该执行什么样的操作。其一般格式如下:
condition 外面的括号是必需的。condition 是用关系运算符和逻辑运算符连接而成的关系判断表达式,其结果是 1(“真”)或 0(“假”),分别表示条件成立或不成立。
语句块 A 或 B 是条件语句的主体部分。如果语句块中包含多条语句,那么其外面必须用花括号{ }
括起来,而且每条语句末尾必须用分号;
结束。但如果语句块中只有一条语句,则花括号可以不写,但是为了方便以后增加语句,建议只有一条语句时也写上花括号。
2.3.1 只使用if语句
条件语句还有另一种比较简化的形式,就是当判断条件成立时执行某些操作,不成立时则结束该条件语句的执行:
- 无论条件语句的执行结果如何,程序总是按照顺序执行的原则,在条件语句结束以后,继续顺序执行跟在它后面的语句。
2.3.2 if else语句的嵌套
if-else 语句的嵌套就是在一个 if-else 语句{ }
括号内的语句块中又包含了另外一个 if-else 语句。其一般格式如下:
2.4 C语言switch case语句的用法
在C语言中,应用条件语句 if-else 可以很方便地使程序实现两个分支,但是如果出现多个分支的情况,虽然可以使用 if-else 语句的嵌套,但是程序会显得比较复杂,不易阅读。
为了实现多个条件分支的选择,C语言提供了 switch case 开关语句。
其一般格式如下:
switch(表达式) //表达式的值只能在下面的 case 值表中出现一次
{
case 值 1:语句序列 1;break; //break 语句的功能是跳出 switch 语句,执行其后面的语句
case 值 2:语句序列 2;break;
case 值 3:语句序列 3;
case 值 4:语句序列 4; //如果没有 break 语句,则会自动继续执行后续 case 的语句序列
……
case 值 n:语句序列 n;break;
default:语句序列n+1; //default 部分是可选项
}
运行 switch 开关语句时,根据表达式的求值结果,选取{ }
括号中的一个 case 分支开始执行。当表达式的值等于值 i 时,就执行 case 值 i 后面的语句序列 i。如果表达式的值没有出现在任何 case 后面,则执行 default 后面的语句序列 n+1。如果没有 default 部分,则结束 switch 语句,执行其后面的语句。
case 后面的值 i 的类型必须和表达式结果值的类型一致。
多个 case 可以共用一组语句序列,即某些 case 的语句序列可为空。比如:
switch(表达式)
{
case 值 1:
case 值 2:
case 值 3:语句序列 3;
}
上述代码中,当表达式的值为值 1 或值 2 或值 3 时,执行相同的语句序列 3。
3. C语言三种循环结构
C语言中的循环控制结构有 3 种基本形式:
-
while 循环语句:当条件成立时,重复操作,否则退出循环
-
do-while 循环语句:重复操作,直到条件不成立时退出循环
-
for 循环语句:用循环变量准确控制重复操作的次数
3.1 while 循环
在C语言中,while 是一种基本的循环,do while 是它的一种变体,有时候两者可以互换。
while 语句适用于“当条件成立时重复操作”的循环控制结构,因而常被称作当型循环。其一般格式如下:
while (condition)
{
循环体; //一条或多条 C 语句
}
condition 就是一个关系判断表达式,它与 if 语句中的 condition 一样,其外面的括号是必需的。循环体是 while 语句的主体部分,是需要重复操作的一条或多条 C 语句,它包含多条语句时,其外侧必须加上花括号{ }
。
如果关系判断表达式 condition 的结果为“真”,就执行循环体里面的语句,之后再次判断 condition,如果结果还是为“真”,则再次执行循环体里面的语句,如此重复操作,直到 condition 的结果为“假”时,不再执行循环体里面的语句,而退出 while 语句,继续执行后续语句。
在循环体内必须存在一条语句,执行后能够改变 condition 中的变量的值,从而使 condition 的判断结果发生变化,出现结果为“假”的情况,终止循环。否则这个循环将会一直重复执行下去,出现“死循环”。
while 语句和 if 语句都是根据关系判断表达式 condition 的判断结果来决定是否执行其主体部分的语句块。两者的不同之处在于,当 condition 为“真”时,if 语句中的主体部分语句块只执行一次,而 while 语句中的循环体会重复执行多次,直到 condition 为“假”才终止循环(见下图)。
另外,while 语句和 if 语句一样,不要在其主体部分外的花括号{ }
后面加上分号。分号只出现在 while 语句循环体内的语句后面。
3.1.1 while语句中的break和continue
break介绍
//break 代码实例
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
break;
printf("%d ", i);
i = i+1;
}
return 0;
}
这里代码输出的结果是什么?(1 2 3 4 )
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
总结:
break在while循环中的作用:
-
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。
continue介绍
//continue 代码实例1
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
continue;
printf("%d ", i);
i = i+1;
}
return 0;
}
这里代码输出的结果是什么?(1 2 3 4 死循环)
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
//continue 代码实例2
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
i = i+1;
if(i == 5)
continue;
printf("%d ", i);
}
return 0;
}
这里代码输出的结果是什么?(2 3 4 6 7 8 9 10 11)
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
2 3 4 6 7 8 9 10
总结
continue在while循环中的作用就是:
- continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
3.2 do while 循环
do-while 语句适用于“重复操作直到条件不成立为止”的循环控制结构,因而常被称作直到型循环。其一般格式如下:
do
{
循环体; //一条或多条 C 语句
}
while (condition);
do-while 循环语句是在执行循环体之后才检查 condition 表达式的值,所以 do-while 语句的循环体至少执行一次。
跟 while 语句一样,要确保 do-while 语句的循环体部分修改了 condition 中的某个变量,从而改变 condition 的判断结果,能够结束循环,否则循环将永远重复下去,成为“死循环”。
- 特别注意:和 while 语句不一样的是,要在 do-while 语句的 condition 外的括号后面加上分号。
3.2.1 do while循环中的break和continue
#include <stdio.h>
int main()
{
int i = 10;
do
{
if(5 == i)
break;
printf("%d\n", i);
}while(i<10);
return 0; }
#include <stdio.h>
int main()
{
int i = 10;
do
{
if(5 == i)
continue;
printf("%d\n", i);
}while(i<10);
return 0; }
3.3 for循环
前面学习的 do-while 语句和 while 语句都适合于解决循环次数未知的重复操作,在C语言中,如果已知重复操作的次数,可以使用 for 循环语句,其一般格式如下:
for(循环变量初始化;循环条件;循环变量增量)
{
循环体 //一条或多条 C 语句
} //若循环体内只有一条语句,则花括号可以不写
循环变量必须在 for 循环语句之前被声明过,一般定义为 int 型。循环变量增量一般情况下是递增或递减循环变量的语句,比如 i++、i–、++i、i-=2、i=i+2、i%=4 等等。
- 循环变量赋初值;
- 判断循环条件,如果成立,执行循环体内的语句;如果不成立,则转到步骤 5;
- 执行循环变量增量语句;
- 转回步骤 2 继续执行;
- 循环结束,执行 for 循环语句后面的语句。
3.3.1 for循环语句的嵌套
如果把一个 for 循环语句放在另一个 for 循环语句的循环体中,就构成了 for 循环的嵌套。其一般格式如下:
for(外层循环变量 i 初始化;外层循环条件;外层循环变量 i 增量)
{
……
for(内层循环变量 j 初始化;内层循环条件;内层循环变量 j 增量)
{
内层循环体
}
……
}
现在我们对比一下for循环和while循环。
int i = 0;
//实现相同的功能,使用while
i=1;//初始化部分
while(i<=10)//判断部分
{
printf("hehe\n");
i = i+1;//调整部分
}
//实现相同的功能,使用while
for(i=1; i<=10; i++)
{
printf("hehe\n");
}
可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹;for循环使用的频率也最高。
3.2.2 for循环中的break和continue
我们发现在for循环中也可以出现break和continue,他们的意义和在while循环中是一样的。
但是还是有些差异:
//代码1
#include <stdio.h>
int main()
{
int i = 0;
for(i=1; i<=10; i++)
{
if(i == 5)
break;
printf("%d ",i);
}
return 0;
}
//代码2
#include <stdio.h>
int main()
{
int i = 0;
for(i=1; i<=10; i++)
{
if(i == 5)
continue;
printf("%d ",i);
}
return 0;
}
3.2.3 for语句的循环控制变量
建议:
-
不可在for 循环体内修改循环变量,防止 for 循环失去控制。
-
建议for语句的循环控制变量的取值采用“前闭后开区间”写法。
int i = 0;
//前闭后开的写法
for(i=0; i<10; i++)
{}
//两边都是闭区间
for(i=0; i<=9; i++)
{}
3.2.4 一些for循环的变种
#include <stdio.h>
int main()
{
//代码1
for(;;)
{
printf("hello\n");
}
//for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。
//代码2
int i = 0;
int j = 0;
//这里打印多少个hello?
for(i=0; i<10; i++)
{
for(j=0; j<10; j++)
{
printf("hello\n");
}
}
//代码3
int i = 0;
int j = 0;
//如果省略掉初始化部分,这里打印多少个hello?
for(; i<10; i++)
{
for(; j<10; j++)
{
printf("hello\n");
}
}
//代码4-使用多余一个变量控制循环
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hello\n");
}
return 0;
}
3.4 练习
- 计算 n的阶乘。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;
int n = 0;
int ret = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
ret *= i;
}
printf("%d\n", ret);
return 0;
}
- 计算 1!+2!+3!+……+10!
#include <stdio.h>
int main()
{
int i = 0;
int n = 0;
int ret = 1;
int sum = 0;
for (n = 1; n <= 10; n++)
{
ret = 1;//计算n的阶乘之前,把ret初始为1
for (i = 1; i <= n; i++)
{
ret *= i;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
由于
2!=2*1!
3!=3*2!
4!=4*3!
…………
因此上面代码可以改进为下面代码,仅需一个for循环:
#include <stdio.h>
int main()
{
int i = 0;
int n = 0;
int ret = 1;
int sum = 0;
for (n = 1; n <= 10; n++)
{
ret *= n;
sum +=ret;
}
printf("%d\n", sum);
return 0;
}
- 在一个有序数组中查找具体的某个数字n。(二分查找)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;//要查找的数字
//在arr这个有序的数组中查找k的值
int sz = sizeof(arr) / sizeof(arr[0]);//数组的元素个数
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
printf("找到了,下标是:%d\n", mid);
break;
}
}
if (left > right)
{
printf("找不到了\n");
}
return 0;
}
- 编写代码,演示多个字符从两端移动,向中间汇聚。
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main()
{
char arr1[] = "Welcome to China!!";
char arr2[] = "##################";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);//睡眠1秒
system("cls");//清空屏幕
left++;
right--;
}
printf("%s\n", arr2);
return 0;
}
- 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成,如果三次均输入错误,则退出程序。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;
char password[20] = { 0 };
//假设正确的密码是字符串“123456”
for (i = 0; i < 3; i++)
{
printf("请输入密码:");
scanf("%s", password);
//if (password == "123456")//这种写法是错误的,两个字符串比较,不能使用==,应该使用strcmp
if (strcmp(password, "123456") == 0)
{
printf("登录成功\n");
break;
}
else
{
printf("密码错误,重新输入!\n");
}
}
if (i == 3)
printf("三次密码均错误,推出程序\n");
return 0;
}
- 猜数字游戏
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("**********************************\n");
printf("*********** 1.play **********\n");
printf("*********** 0.exit **********\n");
printf("**********************************\n");
}
//RAND_MAX--rand函数能返回随机数的最大值。
void game()
{
//猜数字游戏的实现
//1.生成随机数
//rand函数返回了一个0-32767之间的数字
//时间 - 时间戳
int random_num = rand() % 100 + 1;//%100的余数是0-99,然后+1,范围就是1-100
//2.猜数字
int input = 0;
while (1)
{
printf("请输入猜的数字>:");
scanf("%d", &input);
if (input > random_num)
{
printf("猜大了\n");
}
else if (input < random_num)
{
printf("猜小了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned)time(NULL));
do
{
menu();//打印菜单
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新输入!\n");
break;
}
} while (input);
return 0;
}