「C++」 循环和分支语句
循环和关系表达式
- 指定运行次数的循环
- for loop
- 指定条件的循环
- while loop
- do-while loop
for 循环
1 |
|
- 每次循环前计算测试表达式的值
- 若测试表达式为真(非零),依次执行 statement 和 update_expr
- 若测试表达式为假,结束循环
初始化部分允许声明变量,作用域在 for 循环内部
表达式和语句:
任何值或任何有效的值和运算符的组合都是表达式,每个表达式都有值
- 10 是值为 10 的表达式, 28*20 是值为 560 的表达式
- 赋值表达式
x = 20
的值为左侧成员的值 20,x = y = z = 0
将三个变量设为相同的值 - `maids = (cooks=4) + 3 的值为 7
- 表达式后加分号即成为语句,反之未必
递增运算符和递减运算符:
- n++: 后置递增/递减,先用再改
- ++n: 前置递增/递减,先改再用
只能作用于变量,如
(i+j)++
是非法的
与指针的优先级比较:
- 前置递增/递减运算符和解引用运算符优先级相同,从右到左结合
- 后置递增/递减运算符的优先级比前缀版本高,自左向右结合
*p++
先使指针偏移,再解引用(*p)++
对指针指向的变量执行递增操作
实例:遍历 string
1 |
|
复合语句(语句块)
- 一对花括号括起来的多条语句称为语句块,语法上等同于一条语句
- 复合语句中定义的变量仅在该语句块中有效,且会覆盖语句块外部的同名变量
逗号运算符
在int i, j;
中,逗号是分隔符
实例:反转字符串
1 |
|
关系表达式
共有六种:>, >=, <, <=, ==, !=
,其值为逻辑值 true 或 false
可用于数值、字符、以及 string 对象,不能用于 C 风格字符串
优先级:算术 > 关系 > 逻辑(逻辑非除外)
C 风格字符串的比较用 strcmp 函数,string 比较用关系运算符
while 循环
1 |
|
for 循环和 while 循环的区别:
- for 循环省略测试条件时,默认为 true
- for 循环头部可以声明和初始化局部变量
do-while 循环
for 和 while 是入口条件 ( entry-condition ) 循环
do-while是出口条件 ( exit-condition ) 循环
- 先执行循环,再判断条件
- 循环至少执行一次
Range-based for loop
基于范围的for循环
1 |
|
- expression 是要遍历的序列,如初始值列表,数组,vector 或 array 对象
- declaration 定义一个循环控制变量,每次迭代,这个变量会被初始化为expression的下一个元素的值
- 如果要对序列中的元素进行修改,循环变量须声明为引用类型
举例:字符串转大写
1 |
|
自定义类的实现条件:
有迭代器、begin()
, end()
成员方法、重载 !=
比较操作, ++
前置递增,和 *
解引用操作
for_each loop
头文件 <algorithm>
参见: cplusplus.com
1 |
|
将函数 fn 作用于范围 [first, last) 内对应的每个元素
- fn 可以是函数指针或者移动可构造函数对象
- 如果要修改元素,fn 的参数须使用引用
- fn 的返回值将被忽略
举例:字符串转小写
1 |
|
循环和文本输入
使用 cin 进行输入,使用特殊的哨兵字符(如 #)结束输入
例:统计从开始到 # 为止,非空白符的字符数
1
2
3
4
5
6
7
8
9char ch;
cin >> ch;
int count = 0;
while(ch != '#'){
cout << ch;
++count;
cin >> ch;
}
cout << " " << count;输入:
hello world#test
输出:helloworld 10
使用
cin.get()
逐个读取字符例:统计字母、空白、数字字符和其它字符的个数
1
2
3
4
5
6
7
8
9int r[4] = {0};
char c;
while((c = cin.get()) != EOF){
if(isalpha(c))r[0]++;
else if(c == ' ')r[1]++;
else if(isdigit(c))r[2]++;
else r[3]++;
}
文件尾条件:
- EOF 是在
<iostream>
中定义的符号常量,一般为-1
- Unix Shell 中在行首按 Ctrl+D 输入 EOF
- Windows 命令行在行首按 Ctrl+Z 并按回车输入 EOF
- 检测到 EOF 后,cin 将输入流状态的 eofbit 和 failbit 设为 1,阻断后续读取操作
- eofbit 被设置时,
cin.eof()
返回 true; eofbit 或 failbit 被设置为 1 时,cin.fail()
返回 true cin.clear()
可以重置输入流状态以恢复输入
检测输入是否结束( 遇到 EOF 等)
- while(cin.eof() == false)
- while(cin.fail() == false)
- while(!cin.fail())
- while(cin)
- while(cin >> ch)
- while(cin.get(ch))
- while((ch = cin.get()) != EOF)
cin.get(ch) 遇到 EOF 时不会将非 char 值 EOF 赋给 ch
分支语句和逻辑运算符
if 语句
1 |
|
逻辑运算符
逻辑与 &&
, 逻辑或 ||
, 逻辑非 !
&&
和||
自左向右求值,具有短路特性:&&
遇到假以及||
遇到真就会立即停止,右侧的表达式不会再执行- 逻辑非
!
:将非 0 值变为 false, 0 变为 true - 优先级:逻辑非 > 算术 > 关系 > 逻辑与 > 逻辑或
- 保留字 and, or, not 提供了逻辑运算符的另一种方式,但它们不是关键字
例:判断 year 是否为闰年
1 |
|
条件运算符
expr1 ? expr2 : expr3
根据 expr1 的真假决定取哪个值,或者给哪个变量赋值
1 |
|
switch 语句
1 |
|
- switch 的 expression 必须是整型 (包括字符型)、枚举类型或者 class,其中 class 有一个单一的转换函数将其转换为整型或枚举类型
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量
- break 是可选的,没有显式跳转时,会进入下一个 case 继续执行
- 如果所有分支都不匹配,则执行 default 分支,该分支可选
break, continue 和 goto
- break: 从 switch 或循环中跳出
- 如果有多层循环,break 只能跳出当前所在的循环
- continue: 跳过本次循环剩余的代码,开始下一次循环
- goto 可以调到任意位置的标号行,常用于终止深度嵌套
1 |
|
文件操作
通过文件可以将数据持久化
文件类型分为两种:
- 文本文件:文件以文本的ASCII码形式存储
- 二进制文件:文件以文本的二进制形式存储
一、文件输入输出流
头文件:<fstream>
操作文件的三大类:
- ifstream:读操作
- ofstream:写操作
- fstream:读写操作
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 以追加方式写文件 |
ios::trunc | 如果文件存在先删除,再创建 |
ios::binary | 二进制方式 |
文件打开方式可以配合使用,利用|
操作符
例如:用二进制方式写文件 ios::binary | ios::out
文本文件 - 读
1 |
|
读取文件的四种方式:
char buf[1024] = {0}; while(fin >> buf){ cout<<buf<<endl; }
1
2
3
4
2. ```c++
char buf[1024] = {0};
while(fin.getline(buf, sizeof(buf))){...}string buf; while(getline(fin,buf)){...}
1
2
3
4
4. ```c++
char c;
while( (c = fin.get()) != EOF ){cout<<c;}
文本文件 - 写
1 |
|
二进制文件 - 写
以二进制方式对文件进行读写操作
打开方式要指定为 ios::binary
二进制方式写文件主要利用流对象调用成员函数 write
函数原型:ostream& write(const char* buffer, int len);
注:字符指针bufer指向内存中一段存储空间,len是读写的字节数
1 |
|
二进制文件 - 读
二进制方式读文件主要利用流对象调用成员函数 read
函数原型:istream& read(char* buffer, int len);
注:字符指针bufer指向内存中一段存储空间,len是读写的字节数
1 |
|
二、重定向版
头文件:<cstdio>
格式:FILE* freopen(const char* __filename, const char* __modes, FILE* __stream);
参数说明:
mode:文件打开的模式,和fopen中的模式(r/w)相同
stream:文件指针,通常使用标准流文件(stdin/stdout/stderr)
参数 | 含义 |
---|---|
stdin | 标准输入流,默认为键盘 |
stdout | 标准输出流,默认为屏幕 |
stderr | 标准错误流,一般默认为屏幕 |
通过调用 freopen
,就可以修改标准流文件的默认值,实现重定向
代码模板:
1 |
|
三、fopen版
头文件:<cstdio>
实例:
1 |
|
打开文件
格式:FILE* fopen(const char*__filename,const char*__modes);
- 读写方式(可组合):
modes | 含义 | |
---|---|---|
w | write | 写,若文件存在会清空文件,若不存在则创建文件 |
r | read | 读,不具备清空或创建功能 |
a | append | 追加 |
+ | 可读可写 | |
b | binary | 二进制 |
读写文件
以字符方式读写
fgetc()
,fputc()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16FILE* fin, * fout;
fout = fopen("char1.txt","w");
//字符形式读写文件
char str[] = "This is a string";
for (int i = 0; i < strlen(str);i++){
fputc(str[i],fout);
}
fclose(fout);
fin = fopen("char1.txt", "r");
char key = fgetc(fin);
while(key != EOF){
putchar(key);
key = fgetc(fin);
}
fclose(fin);以字符串方式读写
fgets()
,fputs()
1
2
3
4
5
6
7
8
9
10
11FILE* fin, * fout;
fout = fopen("char1.txt","w");
char str[] = {"This is a string"};
fputs(str, fout);
fclose(fout);
fin = fopen("char1.txt", "r");
char buf[1024];
fgets(buf, 1024, fin);
puts(buf);
fclose(fin);格式化读写
fprintf()
,fscanf()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Person{
public:
char m_Name[64];
int m_Age;
};
void test04(){
Person p[3]= {{"张三", 18}, {"李四", 20}, {"王五", 19}};
FILE* fout = fopen("person2.txt","w");
for (auto & i : p){
fprintf(fout,"%s\t%d\n", i.m_Name,i.m_Age);
}
fclose(fout);
FILE* fin = fopen("person2.txt", "r");
Person buf;
while (fscanf(fin, "%s\t%d\n", buf.m_Name, &buf.m_Age) != EOF){
printf("%s\t%d\n", buf.m_Name, buf.m_Age);
}
fclose(fin);
}结构化读写
fread()
,fwrite()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Person{
public:
char m_Name[64];
int m_Age;
};
void test05(){
Person p[3]= {{"张三", 18}, {"李四", 20}, {"王五", 19}};
FILE* fout = fopen("person2.txt","w");
fwrite(&p[0], sizeof(Person), 3, fout);
fclose(fout);
FILE* fin = fopen("person2.txt", "r");
Person buf[3];
fread(buf, sizeof (Person), 3, fin);
for (auto & i : buf){
printf("%s\t%d\n",i.m_Name, buf->m_Age);
}
fclose(fin);
}
关闭文件
fclose(文件指针)
如果把 fopen 版的改成读写标准输入输出,只需赋值 fin=stdin;
, fout=stdout;
即可,不要调用 fopen
和 fclose
。