文章目录
2.3 选择结构
2.3.1 if语句
这个比较简单,if语句的格式如下:
// 如果满足条件,执行{}中的语句
if(条件){
…
}
// 如果条件成立,执行第一个{}中的内容;否则执行第二个{}中的内容
if(条件){
…
}else{
…
}
// 先判断条件A是否成立,成立则执行第一个{}中的内容,不成立则判断条件B是否成立,成立则执行第二个{}中的内容,不成立则执行第三个{}中的内容
if(条件A){
…
}else if(条件B){
…
}else{
…
}
小tips:在if的条件中
,如果表达式是“n != 0”,那么可以直接写成“n”。如果表达式是“n == 0”,那么可以直接写成“!n”。
2.3.2 if语句的嵌套
if语句的嵌套是指在if或者else的执行内容中再次使用if语句。比如:
if(){
if(){
}else{
}
}else{
if(){
}else{
}
}
2.3.3 switch语句
可以在条件比较多的情况精炼语句,格式如下:
switch(条件表达式){
case 常量表达式1:
……
break;
case 常量表达式2:
……
break;
……
case 常量表达式n:
……
break;
default:
…
}
switch会判断条件表达式的结果,例如,如果等于常量表达式2,程序就会进入case 常量表达式2这条分支中,执行其中的内容。每个case的下属语句不需要用{}括起来,默认两个case之间的内容属于上一个case。
此外,要注意每个case的结尾都有一个break
,如果没有,程序不会跳出,而是按照顺序往下执行。比如程序进入case 常量表达式2,如果没有break,程序会按照顺序进入case 常量表达式3、case 常量表达式4……一直到遇到下一个break或者程序结束。
2.4 循环结构
2.4.1 while语句
格式如下:
while(条件){
…
}
只要条件满足,就一直执行{}中的内容。
2.4.2 do…while语句
格式如下:
do{
…
}while(条件);
它会先执行{}中的内容,然后再判断条件是否成立。如果条件成立则继续执行{}中的内容。
2.4.3 for语句
常见格式如下:
for(表达式A; 表达式B; 表达式C){
…
}
for循环开始前,
- 先执行表达式A,
- 判断表达式B是否成立,若成立则执行{}中的内容,否则退出循环。
- 执行完{}中的内容后,执行表达式C,然后再返回2。
注意
,我们经常把表达式A写成赋值语句,比如int i=0
之类的。其实在C语言中,是不允许在表达式A里这样定义变量的,但是在C++中这样写却可以。所以大家使用这种写法的时候,记得将文件保存为.cpp。
2.4.4 break和continue语句
break在条件语句switch中使用过,强行退出switch语句。除此之外,它也用于退出当前的循环语句。
#include <stdio.h>
int main(){
int n, sum=0;
for(int i=1; i<=100; i++){
sum = sum + i;
if(sum >= 2000) break;
}
printf("sum = %d\n", sum);
return 0;
}
// 输出结果为:
// sum = 2016
continue与break有些类似,它们都会停止循环的当前轮回。不同的是,break直接结束循环,而continue则是进入循环的下一个轮回。
#include <stdio.h>
int main(){
int sum=0;
for(int i=1; i<=5; i++){
if(i % 2 == 1) continue;
sum = sum + i;
}
print("sum = %d\n", sum);
return 0;
}
// 输出结果为:
// sum = 6
2.5 数组
2.5.1 一维数组
数组是把相同数据类型
的变量组合在一起而产生的数据集合,是从某个地址开始连续
若干个位置形成的元素集合。
一维数组的格式定义如下:
数据类型 数组名[数组大小];
==注意:数组大小必须是整数常量,不可以是变量。==然后以数组名[下标]
的格式访问。而且能访问的下标范围为0~(数组大小-1)
。
除了定义一个一维数组外,我们还需要对它进行初始化。初始化数据用逗号隔开,并用大括号括起来。比如:
int a[10] = {5, 3, 2, 6, 8, 4};
总共10个元素,我们对其中6个进行了赋值,其余的默认赋值为0。但是没有赋初值的数组中的值是随机数,所以我们如果想把数组中的所有元素给赋值为0,我们只需要把第一个元素赋值为0或者只用一个大括号表示:int a[10] = {0}
或者int a[10] = {}
。但是书中更推荐使用memset
函数。
2.5.2 二维数组
二维数组就是一维数组的扩展,格式如下:
数据类型 数组名[第一维大小][第二位大小];
二维数组中的元素访问和一维数组类似:数组名[下标1][下标2]
。同样下标从0开始。
我们可以将二维数组看作是一维数组的每一个元素都是一个一维数组。比如a[2][3]
,它的第0行元素就是a[0][0]
、a[0][1]
、a[0][2]
,可以看成是一维数组a[2]
中a[0]
的元素。
二维数组初始化的时候,要按照第一维的顺序依次用打括号给出第二维的初始化情况,然后用逗号隔开,并用大括号全部括住。比如:
int a[5][6] = {{3,1,2}, {8,4}, {}, {1,2,3,4,5}};
与一维数组的初始化类似,没有赋值的部分都默认赋值为0。我们这里要特别注意数组名和通过数组名取元素的不同,数组名代表的是第一个元素的地址。在通过scanf读入数据的时候要注意这一点,从而确定是否添加取址符号&。
特别提醒:如果数组大小较大(大概10^6^级别),则需要定义在主函数外面
,否则会使程序异常退出。因为函数内部定义的局部变量来自系统栈,允许申请的空间较小;而函数外部定义的是全局变量,来自静态存储区,允许申请的空间较大。
此外,多维数组的用法跟二维数组类似,没有什么特殊的。
2.5.4 memset——对数组中每一个元素赋相同的值
对数组中每一个元素赋相同的值有两种函数:fill函数和memset函数。
使用memset函数需要添加string.h
头文件,其格式为:
memset(数组名, 值, sizeof(数组名));
只建议初学者使用memset函数赋0或-1。因为memset使用的是按字节赋值,即对每个字节赋同样的值
。仅赋0或者-1不容易弄错。如果要赋其他值可以使用fill
函数。
2.5.5 字符数组
1. 字符数组的初始化
char str[15] = {'G', 'o', 'o', 'd', ' ', 'S', 't', 'o', 'r', 'y', '!'};
除此之外,字符数组也可以通过直接赋值字符串来初始化(仅限于初始化,其他时候不允许)。
char str[15] = "Good Story!";
2. 字符数组的输入与输出
(1)scanf输入,printf输出
#include <stdio.h>
int main(){
char str[10];
scanf("%s", str);
printf("%s", str);
return 0;
}
// 输入
// TAT TAT TAT
// 输出
// TAT
%c
可以识别空格和换行进行输入,但是%s
通过空格和换行识别一个字符串的结束,所以输入时遇到第一个空格的时候,输入就已经结束,最后输出一个TAT。另外,scanf在使用%s时不需要在数组名前面加取址符号&。
(2)getchar输入,putchar输出
前面已经介绍过,见2.2.4节。
(3)gets输入,puts输出
gets
用来输入一行字符串,并将其存放于一维数组或者二维数组的一维中。
注意
:gets识别换行符\n
作为输入结束的标志,所以scanf完一个整数后,如果要使用gets,需要先用getchar吸收换行符。
puts
输出一行字符串,即,将一维数组或者二维数组的一维在界面上输出,并紧跟一个换行。
#include <stdio.h>
int main(){
char str1[20];
char str2[5][10];
// 读取一行字符串,存放于一维数组
gets(str1);
for(int i=0; i<3; i++){
// 读取一行字符串,存放于二维数组的一维
gets(str2[i]);
}
// 输出一维数组
puts(str1);
for(int i=0; i<3; i++){
// 输出二维数组的一维
puts(str2[i]);
}
return 0;
}
3. 字符数组的存放方式
字符数组的每一位都是一个char型字符,且在一维数组或者二维数组第二维的末尾,都会有一个\0
来表示字符串的结尾。使用gets或者scanf时结束符\0会自动添加,puts和printf也是通过识别\0来结束字符串的输出。
注意
:字符数组的长度一定要比实际存储的字符串长度至少多1,因为结束符\0也要占用一个字符位。此外,int型数组不需要添加\0,只有char型数组需要。如果不是使用scanf的%s格式或者gets来输入字符串,需要在输入的每个字符串的后面加结束符\0。
2.5.6 string.h头文件
提示一下,这里的string.h头文件和C++中的string头文件不是同一个。
-
strlen(字符数组)
:返回字符数组中第一个结束符\0之前的字符的个数。 -
strcmp(字符数组1, 字符数组2)
:按照字典序的原则返回两个字符数组的比较结果。- 如果字符数组1 < 字符数组2,返回一个负整数(不同编译器处理不同,不一定是-1)
- 如果字符数组1 == 字符数组2,返回0
- 如果字符数组1 > 字符数组2,返回一个正整数(不同编译器处理不同,不一定是+1)
-
strcpy(字符数组1, 字符数组2)
:把字符数组2复制给字符数组1,包括结束符\0。 -
strcat(字符数组1, 字符数组2)
:把字符数组2接到字符数组1后面。
2.5.7 sscanf与sprintf
这里的s可以看成是string的意思,它们两个都在stdio.h的头文件中。格式如下:
// 把字符数组str中的内容以%d的格式写到n中,从左至右
sscanf(str, "%d", &n);
// 把n以%d的格式写道str字符数组中,从右至左
sprintf(str, "%d", n);
只要格式正确,还可以进行复杂的格式输入与输出。此外,sscanf也支持正则表达式。