分支语句
void IfFunc() {
bool a = true;
std::cout.setf(std::ios::boolalpha); // 设置cout输出bool值
if (a) { // 表达式结果为 true 或 不等于 0 时,进入 if 分支执行语句
std::cout << "a value: " << a << std::endl;
}
bool b = false;
if (b) { // 表达式结果为 true 或 不等于 0 时,进入 if 分支执行语句
std::cout << "b value: " << b << std::endl;
return; // 进入此分支,函数直接结束,不在执行后边语句
}
std::cout << "not into if (b) " << std::endl;
int c = 100;
std::cout.setf(std::ios::dec); // 设置cout输出十进制值
if (c == 100) {
std::cout << "c == 100, c value: " << c << std::endl;
}
if (c != 100) {
std::cout << "c != 100, c value: " << c << std::endl;
}
if (c > 100) {
std::cout << "c > 100, c value: " << c << std::endl;
}
if (c < 100) {
std::cout << "c < 100, c value: " << c << std::endl;
}
// if 嵌套,建议嵌套不要超过三层,超过三层看能否优化此结构
if (c == 100) {
c = 90;
if (c == 90) {
std::cout << "c == 90, c value: " << c << std::endl;
}
}
}
输出结果:
a value: true
not into if (b)
c == 100, c value: 100
c == 90, c value: 90
void IfElseFunc() {
bool a = true;
std::cout.setf(std::ios::boolalpha); // 设置cout输出bool值
if (a) { // 此条件成立,进入 if 分支,否则进入 else 分支
std::cout << "if a value: " << a << std::endl;
} else {
std::cout << "else a value: " << a << std::endl;
}
int b = 100;
// if else if [else]语法,最后的else分支可选
if (b == 100) { // 条件成立进入if分支,执行后不在执行有else分支,条件不成立执行第一个else分支
std::cout << "b == 100" << std::endl;
} else if (b < 100) { // else if又需要判断条件是否成立,条件成立进入分支,不在执行后边的else分支,条件不成立继续执行后边的else分支
std::cout << "b < 100" << std::endl;
} else { // 此处else无判断条件,前边条件不满足直接进入此分支,这个else分支不是必须项
std::cout << "b > 100" << std::endl;
}
// if else 嵌套
if (b == 100) {
b = 50;
if (b > 50) {
std::cout << "b > 50" << std::endl;
} else {
std::cout << "b <= 50" << std::endl;
}
} else if (b < 100) {
if (b > 50) {
std::cout << "b > 50" << std::endl;
} else if (b < 50){
std::cout << "b < 50" << std::endl;
} else {
std::cout << "b == 50" << std::endl;
}
} else if (b > 100) {
if (b > 50) {
std::cout << "b > 50" << std::endl;
} else if (b < 50){
std::cout << "b < 50" << std::endl;
} else if (b == 50){
std::cout << "b == 50" << std::endl;
}
}
}
输出结果:
if a value: true
b == 100
b <= 50
void SwitchFunc() {
int a = 100;
// switch 语法格式
switch (a) { // 关键字switch,括号中判断类型可以是 bool、整型、枚举
case 0: // case 相当于 if (a == 0)
break; // switch规则默认把每个case分支和default分支都顺序执行一次,break控制从当前位置跳出switch范围,即不在执行后边的分支语句
case 10:
// int s = 10; // 此处编译报错
a = 10; // 可使用switch之外的变量
break;
case 100: { // case 分支也可加一对大括号(语句块),这样就可以定义局部变量,否则不能定义
int b = 10; // 此处定义局部变量编译OK
break;
}
default: // 可选分支(若逻辑处理完整可不用写此分支),此处表示除去case判断的值之外的值进入的分支
;
}
}
- 根据不同的条件进入不同的分支执行任务
- 常见的分支语句 if、if else、switch等
运算符
- 按照运算符优先级顺序来排列,以下例子对所有运算符简单应用
- 通常所见到的 std::cout 中 :: 是作用域运算符,cout 在 std 中包含
void OperatorFunc() { // 优先级由高到底
// 1. [] 数组下标
int arr[2] = {10, 100};
std::cout << "arr[0]: " << arr[0] <<"\tarr[1]: " << arr[1] << std::endl;
// 2. () 圆括号
int s = (arr[0] + arr[0]) * arr[0]; // (10 + 10) x 10
std::cout << "s value: " << s << std::endl;
// 3. . 成员选择(对象)
struct A {
int a;
int b;
};
A t;
t.a = 10;
t.b = 20;
std::cout << "A a value:" << t.a << "\tA b value: " << t.b << std::endl;
// 4. -> 成员选择(对象)
A *p = &t;
std::cout << "A a value:" << p->a << "\tA b value: " << p->b << std::endl; // (&t)->a 访问也可
// 5. - + 负号 正号(可省略)
s = -60 + 10; // 10 为正数,也可写为 s = -60 + +10;
std::cout << "s value:" << s << std::endl;
// 6. (类型) 强制类型转换
s = (int)-100.5;
std::cout << "s value:" << s << std::endl;
// 7. ++ 自增运算符
s = 20;
std::cout << "s++ value:" << s++ << std::endl; // ++ 在后,先打印值,然后值加一
std::cout << "s value:" << s++ << std::endl;
s = 20;
std::cout << "++s value:" << ++s << std::endl; // ++ 在前,先值加一,然后打印值
std::cout << "s value:" << s << std::endl;
// 8. -- 自减运算符
s = 20;
std::cout << "s-- value:" << s-- << std::endl; // -- 在后,先打印值,然后值减一
std::cout << "s value:" << s++ << std::endl;
s = 20;
std::cout << "--s value:" << --s << std::endl; // -- 在前,先值减一,然后打印值
std::cout << "s value:" << s << std::endl;
// 9. * 指针解引用运算符
int *p1 = &s;
std::cout << "*p1 value:" << *p1 << std::endl; // 取出指针指向地址的值
// 10. & 取地址运算符
std::cout << "s value: " << s << "\ts address: " << &s << std::endl;
// 11. ! 逻辑非运算符
bool i = true;
std::cout << "i value: " << i << "\t!i address: " << !i << std::endl;
// 12. ~ 按位取反运算符
s = 20; // 二进制为 1000 0000 0000 0000 0000 0000 0001 0100,最高位为符号位,1 表示有符号
std::cout << std::hex << "s value: 0x" << s << "\t~s value: " << ~s << std::endl;
std::cout << std::dec << "s value: " << s << "\t~s value: " << ~s << std::endl;
unsigned int f = 20; // 二进制为 0000 0000 0000 0000 0000 0000 0001 0100,最高位为符号位,0 表示有符号
std::cout << std::hex << "f value: 0x" << f << "\t~f value: " << ~f << std::endl;
std::cout << std::dec << "f value: " << f << "\t~f value: " << ~f << std::endl;
// 13. sizeof 长度运算符,对于变量括号可省略
std::cout << "struct A length: " << sizeof (A) << "\tA t length: " << sizeof t << std::endl;
std::cout << "s length: " << sizeof (int) << "\tA t length: " << sizeof (s) << std::endl;
// 14. / * % + - 除 乘 取余 加 减,可组合成复杂算数运算
s = 15;
// std::cout << "s / 0 = " << s / 0 << std::endl; // 注意除数不能为零 s / 0
std::cout << "s / 3 = " << s / 3 << std::endl;
std::cout << "s / 6 = " << s / 6 << std::endl;
std::cout << "s / 7 = " << s / 7 << std::endl;
// 会发现上边输出后面两个结果相等,且输出结果没有小数部分,规则是如果除号两侧数据类型都为整型,则结果也是整型
std::cout << "s / 6.0 = " << s / 6.0 << std::endl; // 将一侧数据类型改成浮点型,则结果为浮点型
std::cout << "s / 7.0 = " << s / 7.0 << std::endl;
std::cout << "s * 2 = " << s * 2 << std::endl;
std::cout << "s * 3.5 = " << s * 3.5 << std::endl;
// % 两侧的数据类型只能为整型,取余结果和被取余的数正负号相同
std::cout << "s % 3 = " << s % 3 << std::endl; // 余数为 0
std::cout << "s % 7 = " << s % 7 << std::endl; // 余数为 1
std::cout << "s % 7 = " << s % -7 << std::endl; // 余数为 1
s = -s; // s = -15
std::cout << "s % 3 = " << s % 3 << std::endl; // 余数为 0
std::cout << "s % 7 = " << s % 7 << std::endl; // 余数为 -1
std::cout << "s % 7 = " << s % -7 << std::endl; // 余数为 -1
s = 20;
std::cout << "s + s = " << s + s << std::endl;
std::cout << "s + 3.25 = " << s + 3.25 << std::endl;
std::cout << "s + -3.25 = " << s + -3.25 << std::endl;
std::cout << "s - 35.5 = " << s - 35.5 << std::endl;
std::cout << "s - 3.25 = " << s - +3.25 << std::endl;
std::cout << "s - -3.25 = " << s - -3.25 << std::endl;
// 15. << >> 左移 右移 运算符,左移相当于乘2,右移相当于除以2
s = 3000;
std::cout << "s << 1 = " << (s << 1) << std::endl;
std::cout << "s * 2 = " << s * 2 << std::endl;
std::cout << "s << 2 = " << (s << 2) << std::endl;
std::cout << "s * 2 * 2 = " << s * 2 * 2 << std::endl;
std::cout << "s >> 1 = " << (s >> 1) << std::endl;
std::cout << "s / 2 = " << s / 2 << std::endl;
std::cout << "s >> 2 = " << (s >> 2) << std::endl;
std::cout << "s / 2 / 2 = " << s / 2 / 2 << std::endl;
// 16. > >= < <= == != 大于 大于等于 小于 小于等于 等于 不等于
s = 100;
std::cout.setf(std::ios::boolalpha);
std::cout << "s > 100: " << (s > 100) << std::endl;
std::cout << "s > 50: " << (s > 50) << std::endl;
std::cout << "s >= 100: " << (s > 100) << std::endl;
std::cout << "s >= 101: " << (s > 101) << std::endl;
std::cout << "s < 100: " << (s < 100) << std::endl;
std::cout << "s < 150: " << (s < 150) << std::endl;
std::cout << "s <= 100: " << (s > 100) << std::endl;
std::cout << "s <= 99: " << (s > 99) << std::endl;
std::cout << "s == 100: " << (s == 100) << std::endl;
std::cout << "s == 50: " << (s == 50) << std::endl;
std::cout << "s != 100: " << (s == 100) << std::endl;
std::cout << "s != 50: " << (s == 50) << std::endl;
// 17. & ^ | 按位与 按位异或 按位或
s = 20; // 二进制为 1000 0000 0000 0000 0000 0000 0001 0100
int g = 12; // 二进制为 1000 0000 0000 0000 0000 0000 0000 1100
// s 1000 0000 0000 0000 0000 0000 0001 0100
// &
// g 1000 0000 0000 0000 0000 0000 0000 1100
// 1000 0000 0000 0000 0000 0000 0000 0100
// & 规则,按二进制,s 和 g相同位上同为真(1)才为真,否则为假(0)
std::cout << std::hex << "hex: s & g = 0x" << (s & g) << std::endl;
std::cout << std::dec << "dec: s & g = " << (s & g) << std::endl;
// s 1000 0000 0000 0000 0000 0000 0001 0100
// |
// g 1000 0000 0000 0000 0000 0000 0000 1100
// 1000 0000 0000 0000 0000 0000 0001 1100
// | 规则,按二进制,s 和 g相同位上同为假(0)才为假(0),否则为真(1)
std::cout << std::hex << "hex: s | g = 0x" << (s | g) << std::endl;
std::cout << std::dec << "dec: s | g = " << (s | g) << std::endl;
// s 1000 0000 0000 0000 0000 0000 0001 0100
// ^
// g 1000 0000 0000 0000 0000 0000 0000 1100
// 1000 0000 0000 0000 0000 0000 0001 1000
// ^ 规则,按二进制,s 和 g相同位上值相同就为假(0),值不相同就为真(1)
std::cout << std::hex << "hex: s ^ g = 0x" << (s ^ g) << std::endl;
std::cout << std::dec << "dec: s ^ g = " << (s ^ g) << std::endl;
// 18. && || 逻辑与 逻辑或,按值(不按位)判断真假,注意其短路规则
s = 20;
g = 30;
// && 规则:运算符两边值都为真(或不为零)时才为真,否则为假
std::cout.setf(std::ios::boolalpha);
std::cout << "s && g: " << (s && g) << std::endl;
g = 0;
std::cout << "s && g: " << (s && g) << std::endl;
// || 规则:运算符两边值都为假(或为零)时才为假,否则为真
std::cout << "s || g: " << (s || g) << std::endl;
g = 0;
std::cout << "s || g: " << (s || g) << std::endl;
// 短路规则
g = 30;
int j = 0;
// 先执行 (s && j),判断为假,两个表达式中间以 &&(同为真才为真)相连,所以直接判断为假,不会继续执行后续判断
std::cout << "(s && j) && (s && g): " << ((s && j) && (s && g)) << std::endl;
// (s && g) 为真,是以 && 相连,继续判断(s && g),最终判断(1 || 0)结果
std::cout << "(s && g) && (s && j): " << ((s && g) && (s && j)) << std::endl;
// 先执行 (s && j),判断为假,两个表达式中间以 ||(同为假才为假)相连,继续判断(s && g)为真,最终判断(0 || 1)结果
std::cout << "(s && j) || (s && g): " << ((s && j) || (s && g)) << std::endl;
// (s && g) 为真,是以 || 相连,不在做判断,直接为真
std::cout << "(s && g) || (s && j): " << ((s && g) || (s && j)) << std::endl;
// 19. ?: 条件运算符(三目运算符)
s = 20;
if (s == 20) { // 条件判断 if 实现简单例子
g = s - 10;
} else {
g = s + 10;
}
// 使用条件运算符实现,如果条件 s == 20 为真(true),执行 g = s - 10,否则执行 g = s + 10
s == 20 ? g = s - 10 : g = s + 10;
// 20. = /= *= %= 赋值 除后赋值 乘后赋值 取余后赋值
// += -= <<= >>= 加后赋值 减后赋值 左移后赋值 右移后赋值
// &= ^= |= 按位与后赋值 按位异或后赋值 按位或后赋值
// 这些运算符其实是简化代码编写
s = 10;
s /= 5; // s = s / 5;
s *= 5; // s = s * 5;
s %= 5; // s = s % 5;
s += 5; // s = s + 5;
s -= 5; // s = s - 5;
s <<= 5; // s = s << 5;
s >>= 5; // s = s >> 5;
s &= 5; // s = s & 5;
s ^= 5; // s = s ^ 5;
s |= 5; // s = s | 5;
// 21. , 逗号运算符,当顺序点用,顺序是从左至右,用来顺序求值,优先级最低
int z = 20, x, c, v = 10; // 定义变量
int *k, l; // 注意此处只有 k 为指针类型,l 为 int 类型,使用 decltype 推导变量类型
std::cout << (typeid (int *) == typeid(decltype (k))) << std::endl;
std::cout << (typeid (int) == typeid(decltype (l))) << std::endl;
s = z, v; // z 值赋值给 s 而不是 v,低版本Qt可能编译报错,不支持这样的写法(实际上这种写法无任何意义)
std::cout << std::dec << "s value: " << s << std::endl;
int n = 0;
int arr2[10] = {1, 2, 3, 4, 5, 6, 7, 8};
for (n = 1, n = 2, n = 3; n < 10; ++n) { // 注意使用逗号表达式,此处 n 循环开始值为 3
std::cout << "arr2 index: " << n << "\tarr2 value: " << arr2[n] << std::endl;
}
}
输出结果: // 放在代码块里是因为有和 Markdown 符号冲突的输出
arr[0]: 10 arr[1]: 100
s value: 200
A a value:10 A b value: 20
A a value:10 A b value: 20
s value:-50
s value:-100
s++ value:20
s value:21
++s value:21
s value:21
s-- value:20
s value:19
--s value:19
s value:19
*p1 value:19
s value: 19 s address: 0x65fd54
i value: 1 !i address: 0
s value: 0x14 ~s value: ffffffeb
s value: 20 ~s value: -21
f value: 0x14 ~f value: ffffffeb
f value: 20 ~f value: 4294967275
struct A length: 8 A t length: 8
s length: 4 A t length: 4
s / 3 = 5
s / 6 = 2
s / 7 = 2
s / 6.0 = 2.5
s / 7.0 = 2.14286
s * 2 = 30
s * 3.5 = 52.5
s % 3 = 0
s % 7 = 1
s % 7 = 1
s % 3 = 0
s % 7 = -1
s % 7 = -1
s + s = 40
s + 3.25 = 23.25
s + -3.25 = 16.75
s - 35.5 = -15.5
s - 3.25 = 16.75
s - -3.25 = 23.25
s << 1 = 6000
s * 2 = 6000
s << 2 = 12000
s * 2 * 2 = 12000
s >> 1 = 1500
s / 2 = 1500
s >> 2 = 750
s / 2 / 2 = 750
s > 100: false
s > 50: true
s >= 100: false
s >= 101: false
s < 100: false
s < 150: true
s <= 100: false
s <= 99: true
s == 100: true
s == 50: false
s != 100: true
s != 50: false
hex: s & g = 0x4
dec: s & g = 4
hex: s | g = 0x1c
dec: s | g = 28
hex: s ^ g = 0x18
dec: s ^ g = 24
s && g: true
s && g: false
s || g: true
s || g: true
(s && j) && (s && g): false
(s && g) && (s && j): false
(s && j) || (s && g): true
(s && g) || (s && j): true
true
true
s value: 20
arr2 index: 3 arr2 value: 4
arr2 index: 4 arr2 value: 5
arr2 index: 5 arr2 value: 6
arr2 index: 6 arr2 value: 7
arr2 index: 7 arr2 value: 8
arr2 index: 8 arr2 value: 0
arr2 index: 9 arr2 value: 0
二维数组
void ArrayTwo() {
// 指针数组和数组指针
int (*ae)[2]; // 是一个指针,它指向有2个元素的一维数组,它是指向数组的指针
int *af[2]; // 是一个数组,数组的元素(2个元素存储)都是指针(int *),它是储存指针的数组
// auto 所表示的变量代表后面赋值的 lambda(c++11特性) 函数,函数参数展示了如何传入二维指针
auto Print = [](int **arr, int row, int col) { // 以二重指针方式传参,不能使用arr[i][j]访问,需要手动计算元素位置
for (int i = 0; i < row; ++i) { // 打印二维数组,内存必须连续
for (int j = 0; j < col; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << *((int *)arr + i * col + j) << "\t";
}
std::cout << "\n";
}
};
auto Print2 = [](int arr[][2], int row, int col) { // 以二维数组方式传参,退化为指针
for (int i = 0; i < row; ++i) { // 打印二维数组
for (int j = 0; j < col; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << "\t";
}
std::cout << "\n";
}
};
auto Print3 = [](int arr[2][2], int row, int col) { // 以二维数组方式传参,退化为指针
for (int i = 0; i < row; ++i) { // 打印二维数组
for (int j = 0; j < col; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << "\t";
}
std::cout << "\n";
}
};
auto Print4 = [](int (*arr)[2], int row, int col) { // 以数组指针方式传参,退化为指针
for (int i = 0; i < row; ++i) { // 打印二维数组
for (int j = 0; j < col; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << "\t";
}
std::cout << "\n";
}
};
auto Print5 = [](int *arr[2], int row, int col) { // 以数组指针方式传参,退化为指针
for (int i = 0; i < row; ++i) { // 打印二维数组
for (int j = 0; j < col; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << "\t";
}
std::cout << "\n";
}
};
// 直接指定行数和列数(栈内存)
int a[2][2] = {1, 2, 3, 4}; // 编译时会出警告,不推荐
std::cout << "Print array a: " << std::endl;
Print3(a, 2, 2);
int b[2][2] = {{5, 6}, {7, 8}};
std::cout << "Print array b: " << std::endl;
Print4(b, 2, 2);
// 自推导行数,列数不能省略(栈内存)
int c[][2] = {{9, 10}, {11, 12}};
std::cout << "Print array c: " << std::endl;
Print((int **)c, 2, 2);
int d[][2] = {{9, 10}, {11, 12}}; // Qt14.2 MinGW 64编译器,自动推导行
std::cout << "Print array d: " << std::endl;
Print2(d, 6, 2); // 打印 6 行也不报错,只不过后边值是大于 2 行后是随机值(不推荐这样越界使用)
// 指针创建(堆内存),这种方式创建可能二维指针内存不连续
int **pe;
pe = new int*[2]; // 创建数组指针
for(int i = 0; i < 2; i++) {
pe[i] = new int[2]; // 指针指向对应的数组首地址
}
pe[0][0] = 13; // 赋值
pe[0][1] = 14;
pe[1][0] = 15;
pe[1][1] = 16;
std::cout << "Print array pe: " << std::endl;
Print5(pe, 2, 2);
for (int i = 0; i < 2; ++i) { // 赋值
for (int j = 0; j < 2; ++j) {
pe[i][j] = 17 + i + j;
}
}
std::cout << "Print array pe: " << std::endl;
Print5(pe, 2, 2);
// 释放
for (int i = 0; i < 2; i++)
delete [] pe[i];
delete [] pe;
// 二维数组首地址
std::cout << "array b adderess: \t" << b << std::endl;
std::cout << "array b[0] adderess: \t" << &b[0] << std::endl;
std::cout << "array b[0][0] adderess: \t" << &b[0][0] << std::endl;
// 二维数组名称加上某个数和某行的首地址值相同
std::cout <<"b + 1: " << b + 1 << std::endl;
std::cout <<"b[1]: " << b[1] << std::endl;
// 二维数组总长度
std::cout <<"total b length: " << sizeof b << std::endl; // 2 * 2 * 4
std::cout <<"b[0] length: " << sizeof b[0] << std::endl; // 第一行长度
std::cout <<"member size: " << sizeof b[0] / sizeof (int) << std::endl; // 第一行元素数量
}
输出结果:
Print array a:
arr[0][0] = 1 arr[0][1] = 2
arr[1][0] = 3 arr[1][1] = 4
Print array b:
arr[0][0] = 5 arr[0][1] = 6
arr[1][0] = 7 arr[1][1] = 8
Print array c:
arr[0][0] = 9 arr[0][1] = 10
arr[1][0] = 11 arr[1][1] = 12
Print array d:
arr[0][0] = 9 arr[0][1] = 10
arr[1][0] = 11 arr[1][1] = 12
arr[2][0] = 9 arr[2][1] = 10
arr[3][0] = 11 arr[3][1] = 12
arr[4][0] = 5 arr[4][1] = 6
arr[5][0] = 7 arr[5][1] = 8
Print array pe:
arr[0][0] = 13 arr[0][1] = 14
arr[1][0] = 15 arr[1][1] = 16
Print array pe:
arr[0][0] = 17 arr[0][1] = 18
arr[1][0] = 18 arr[1][1] = 19
array b adderess: 0x65fd20
array b[0] adderess: 0x65fd20
array b[0][0] adderess: 0x65fd20
b + 1: 0x65fd28
b[1]: 0x65fd28
total b length: 16
b[0] length: 8
member size: 2
- 一维数组在内存存储是连续的,二维数组在内存中仍然像一维数组那样连续存储
- 注意二维数组作为函数参数时的用法,具体参照例子