0x00 变量与数据类型

变量必须先定义,才可以使用。不能重名。
变量定义的方式:

  • 单变量或赋值表达式 ```cpp

    include

using namespace std;

int main() { int a = 5; int b, c = a, d = 10 / 2; cout << a << “ “ << b << endl;

  1. return 0;

}

  1. 常用数据类型及范围:
  2. | 类型 | 关键字 | 范围 | 备注 |
  3. | --- | --- | --- | --- |
  4. | 布尔型 | bool | | |
  5. | 字符型 | char | 1字节<br />-128~1270-255 | |
  6. | 整型 | short int | 2字节 | 有符号 |
  7. | 整型 | int | 4字节<br />![](https://cdn.nlark.com/yuque/__latex/959b596e4df9b8939f93d8836012bede.svg#card=math&code=%5B-2%5E%7B31%7D%2C%202%5E%7B31%7D%20-%201%5D&id=nijSD) | 有符号 |
  8. | 整型 | long int | 48字节 | 有符号 |
  9. | 整型 | long | 48字节 | 有符号 |
  10. | 浮点型 | float | 4字节<br />6-7个有效数字 | 有符号 |
  11. | 双浮点型 | double | 8字节<br />15-16个有效数字 | 有符号 |
  12. | 无类型 | void | | |
  13. | 宽字符型 | wchar_t | 24个字节 | `typedef short int wchar_t` |
  14. | 长整型 | long long | 8字节<br />![](https://cdn.nlark.com/yuque/__latex/fdb47d20846b6dbfa226eec865db8e09.svg#card=math&code=%5B-2%5E%7B63%7D%2C%202%5E%7B63%7D%20-%201%5D&id=BiYNI) | 有符号 |
  15. | 长双浮点型 | long double | 16字节<br />18-19位有效数字 | 有符号 |
  16. <a name="bAKOh"></a>
  17. ## 0x01 输入输出
  18. `cin``cout``iostream`头文件中<br />`scanf``printf``cstdio`头文件中
  19. > 在读入字符时,`cin`会过滤空格,`scanf`不会过滤空格
  20. 使用`printf`时:<br />`int`型用`%d`, `long long`型用`%lld`<br />`float`型用`%f`, `double`型用`%lf`<br />用`float, double`等输出保留若干小数时用:`%.4f, %.3lf`<br />最小数字宽度:<br />`%8.3f`表示这个浮点数的最小宽度为8,保留3位小数,不足宽度时补空格<br />`%-8.3f`左对齐<br />`%08.3f`宽度不足时补上0<br />带符号:`%+lf`指明正负号<br />`%`输出时需要用`%%`
  21. <a name="Ecr9G"></a>
  22. ## 0x02 运算符及表达式
  23. 类似于Java<br />不同点:
  24. - 从高精度到低精度转换可以不用强制类型转换(当然用了也是对的)
  25. <a name="xyuv4"></a>
  26. ## 0x03 判断语句
  27. 类似于Java<br />不同点:
  28. - `switch`语句不用用`string`作为条件
  29. <a name="UR7ad"></a>
  30. ## 0x04 循环语句
  31. 类似于Java
  32. <a name="c2M1T"></a>
  33. ## 0x05 数组
  34. 数组的定义:<br />与变量定义类似,`int a[20]`<br />数组的初始化(与Java区别蛮大的):
  35. - `int a[3] = {0, 1, 3}`
  36. - `int b[] = {4, 5, 6}`
  37. - `int c[5] = {1, 2, 3}`定义了一个长度为5的数组`{1, 2, 3, 0, 0}`
  38. - `int d[10] = {0}` 将数组全部初始化为0
  39. :::danger
  40. Java的数组有默认初始化,Javanew出来的都在堆中<br />C++的数组如果定义在函数内,则没有默认初始化<br />C++函数内的变量,包括数组都在**栈中,只有定义在外部才在堆中,且包含初始化。**
  41. :::
  42. 高维数组定义:<br />`int a[10][12]`<br />高维数组初始化:
  43. - `int a[3][4] = {{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}}`
  44. 快速初始化<br />`memset(a, 0, sizeof a)`含义是将从a开始的长度为`sizeof a`字节的空间初始化为0`sizeof`位于`cstring`库中。<br />拷贝<br />`memcpy(b, a, sizeof a)`含义是将a数组整体复制到b数组。注意是**按字节顺序**赋值。
  45. <a name="UWHYr"></a>
  46. ## 0x06 字符串
  47. 字符数组:<br />字符串就是字符数组加上结束符'\0'<br />可以使用字符串来初始化字符数组,但要注意每个字符串的结尾会暗含一个'\0',因此字符数组的长度至少比字符串长度大1<br />合法的字符数组初始化:
  48. - `char a1[] = {'C', '+', '+'}`
  49. - `char a2[] = {'C', '+', '+', '\0'}`
  50. - `char a3[] = "C++"`
  51. 非法初始化:`char a4[3] = "C++"`
  52. 字符数组当字符串输入:
  53. - `scanf("%s", a1)`
  54. - `cin >> a2`
  55. - `cin >> a3 + 1`
  56. :::success
  57. 输入字符串时,碰到回车或空格就会停止
  58. :::
  59. 问题:如何读入一行?<br />`fgets(a, 100, stdin)`表示从标准输入中读取不超过100个字符的一行数据到字符数组`a`中。**会读取末尾的回车,如果有的话**。<br />`cin.getline(a, 100)`表示从标准输入中读取不超过100个字符的一行数据到字符数组`a`中。**不会读取末尾的回车**。
  60. 字符数组当字符串输出:
  61. - `cout << a1 << endl`会得到`C++`
  62. - `printf("%s\n", a2)`会得到`C++`
  63. - `puts(a2)`会得到`C++`,参数必须是字符数组。
  64. - `cout << a2 + 1 << endl`会得到`++`
  65. :::success
  66. 如果字符数组没有`\0`,不能按照字符串输出<br />输出碰到回车或空格,原样输出,直至遇到`\0`
  67. :::
  68. 常用库函数:
  69. | int strlen(char[] s) | 参数:字符数组<br />返回值:字符数组中存储的字符串的长度(不包括'\\0') | `cstring`头文件中 |
  70. | --- | --- | --- |
  71. | int strcmp(char[] a, char[] b) | 参数:两个字符数组<br />返回值:0, 1, -1分别表示a == b, a > b, a < b | `cstring`头文件中 |
  72. | void strcpy(char[] b, char[] a) | 参数:两个字符数组<br />作用:将a复制给b | `cstring`头文件中 |
  73. 标准字符串:<br />可变长,可修改的字符序列,比字符数组更好用。需引入头文件`string`
  74. 初始化:
  75. - `string s1`定义一个空字符串
  76. - `string s2 = s1`,将`s1`拷贝到`s2`
  77. - `string s3 = "zdkk"`,用字符串字面值定义
  78. - `string s4(4, 'k')`定义一个字符串`s4 = "kkkk"`
  79. - `string s5 ("12345", 1, 3)`定义一个字符串`s5 = "234"`(`1, 3`表示从下标1开始连续3个字符)
  80. :::danger
  81. string s = 'k' // 非法<br />string s;<br />s = 'k' // 合法,很神奇
  82. :::
  83. 输入:<br />不能用`scanf()`<br />正确方式:`cin >> s`<br />`getline(cin, s)`表示读一行到字符串`s`中,**不会读取末尾的回车**。
  84. 输出:
  85. - 可以用`printf`,需要调用函数。`printf("%s\n", s.c_str())`
  86. `s.c_str()`返回字符串`s`的首字符地址。
  87. - `puts(s.cstr())`
  88. - `cout << s << endl`
  89. 常用函数
  90. - `s.empty()`如果返回0,说明不为空。
  91. - `s.length(), s.size()`返回字符串长度
  92. - 字符串比较,直接用`==`即可,运算符重载
  93. - 字符串拼接,`s1 += s2, s1.append(s2)`
  94. - 遍历字符串,`for (auto &c : s)`
  95. - 插入字符串,`s.insert(3, s2)`在下标3处插入s2
  96. - 找子串,`s.substr(1, 3), s.substr(1)`,前者是从1开始的长度为3的子串,后者是从1开始的直至末尾的子串
  97. - 删除某段子串,`s.erase(1, 3)`表示删除从下标1开始的长度为3的子串。
  98. - 查看最后一个字符,`s.back()`
  99. - 删除最后一个字符,`s.pop_back()`
  100. - 字符串查找,`s.find(s2, 0)`s串下标0的地方开始,查找s2的位置,如果不存在返回`string::npos`
  101. - 字符串反转,`reverse(s.begin(), s.end())`
  102. :::danger
  103. 字符串拼接必须保证有一方为字符串变量,另一方可以是字符串变量,字符串字面量或者字符<br />s += 'k' // 合法<br />s.append('k') // 非法,很神奇
  104. :::
  105. <a name="eJeG8"></a>
  106. ## 0x07 函数
  107. C++的函数需要函数声明和函数定义<br />在函数内部可以使用静态变量`static int a = 0`,在多次调用时只会被初始化一次,等价于只能在函数内部使用的全局变量<br />函数参数可以有默认值`int foo(int a, int b = 10, int c = 15)`<br />数组作为参数传入,用`sizeof`测其长度,其实得到的结果是指针的大小<br />数组作为参数传入,除了第一维外,都需要明确指明大小
  108. <a name="SEUuQ"></a>
  109. ## 0x08 类与结构体
  110. 类中的变量和函数被统一称为类的成员变量。<br />`private`后面的内容是私有成员变量,在类的外部不能访问;<br />`public`后面的内容是公有成员变量,在类的外部可以访问。
  111. ```cpp
  112. #include <iostream>
  113. #include <cstring>
  114. #include <algorithm>
  115. #include <cmath>
  116. using namespace std;
  117. class Person {
  118. private:
  119. int age, height;
  120. double money;
  121. string books[100];
  122. public:
  123. string name;
  124. void say() {
  125. cout << "I'm" << name << endl;
  126. }
  127. int get_age() {
  128. return age;
  129. }
  130. int get_money() {
  131. return money;
  132. }
  133. void add_money(double x) {
  134. money += x;
  135. }
  136. };
  137. int main() {
  138. Person c;
  139. c.name = "zdkk";
  140. c.add_money(10000);
  141. cout << c.get_age() << " " << c.get_money() << endl;
  142. return 0;
  143. }

类与结构体定义的唯一区别在于类中不写作用域,默认是private,而结构体中默认为public
类中的变量类似于局部变量,也没有默认初始化。

  1. // 类与结构体的构造函数与初始化
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <cmath>
  6. using namespace std;
  7. struct Person {
  8. int age, height;
  9. double money;
  10. Person() {};
  11. // Person(int _age, int _height, int _money) {
  12. // age = _age;
  13. // height = _height;
  14. // money = _money;
  15. // }
  16. Person(int _age, int _height, int _money) : age(_age), height(_height), money(_money){}
  17. };
  18. int main() {
  19. Person p;
  20. Person c1(18, 180, 100);
  21. Person c2 = {5, 100, 200};
  22. Person c3 = Person(15, 150, 1000);
  23. cout << c1.money << endl;
  24. return 0;
  25. }

0x09 指针和引用

指针指向存放变量的值的地址。因此我们可以通过指针来修改变量的值。

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. int a = 10;
  5. int *p = &a, b = 20;
  6. cout << p << endl;
  7. }

数组名是一种特殊的指针,指向数组开始地址

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. char c;
  5. int a[5] = {1, 2, 3, 4, 5};
  6. cout << (void *)&c << endl;
  7. cout << a << endl;
  8. cout << (void*)&a[0] << endl;
  9. cout << (void*)&a[1] << endl;
  10. cout << (void*)&a[2] << endl;
  11. cout << (void*)&a[3] << endl;
  12. cout << (void*)&a[4] << endl;
  13. }

指针支持的运算

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. char c;
  5. int a[5] = {1, 2, 3, 4, 5};
  6. int *p = a;
  7. cout << *p << endl;
  8. cout << *(p + 1) << endl;
  9. cout << *(a + 2) << endl;
  10. cout << p[3] << endl;
  11. cout << p[10] << endl; // 出大问题,这里居然不报越界,直接输出不确定值
  12. }

引用和指针类似,相当于给变量起了个别名。

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. char c;
  5. int a = 1;
  6. int &p = a;
  7. p = 10;
  8. cout << a << endl;
  9. }

链表

  1. #include <iostream>
  2. using namespace std;
  3. struct Node {
  4. int val;
  5. Node* next;
  6. Node(int _val) : val(_val), next(NULL) {}
  7. };
  8. int main() {
  9. Node node = Node(1); // 这种写法返回的是Node对象
  10. cout << node.val << endl;
  11. Node *p = new Node(2); // 这种写法返回的是Node对象的引用
  12. cout << p->val << endl
  13. }