0x00 变量与数据类型
变量必须先定义,才可以使用。不能重名。
变量定义的方式:
using namespace std;
int main() { int a = 5; int b, c = a, d = 10 / 2; cout << a << “ “ << b << endl;
return 0;
}
常用数据类型及范围:| 类型 | 关键字 | 范围 | 备注 || --- | --- | --- | --- || 布尔型 | bool | | || 字符型 | char | 1字节<br />-128~127或0-255 | || 整型 | short int | 2字节 | 有符号 || 整型 | int | 4字节<br /> | 有符号 || 整型 | long int | 4或8字节 | 有符号 || 整型 | long | 4或8字节 | 有符号 || 浮点型 | float | 4字节<br />6-7个有效数字 | 有符号 || 双浮点型 | double | 8字节<br />15-16个有效数字 | 有符号 || 无类型 | void | | || 宽字符型 | wchar_t | 2或4个字节 | `typedef short int wchar_t` || 长整型 | long long | 8字节<br /> | 有符号 || 长双浮点型 | long double | 16字节<br />18-19位有效数字 | 有符号 |<a name="bAKOh"></a>## 0x01 输入输出`cin`和`cout`在`iostream`头文件中<br />`scanf`和`printf`在`cstdio`头文件中> 在读入字符时,`cin`会过滤空格,`scanf`不会过滤空格使用`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 />`%`输出时需要用`%%`<a name="Ecr9G"></a>## 0x02 运算符及表达式类似于Java<br />不同点:- 从高精度到低精度转换可以不用强制类型转换(当然用了也是对的)<a name="xyuv4"></a>## 0x03 判断语句类似于Java<br />不同点:- `switch`语句不用用`string`作为条件<a name="UR7ad"></a>## 0x04 循环语句类似于Java<a name="c2M1T"></a>## 0x05 数组数组的定义:<br />与变量定义类似,`int a[20]`<br />数组的初始化(与Java区别蛮大的):- `int a[3] = {0, 1, 3}`- `int b[] = {4, 5, 6}`- `int c[5] = {1, 2, 3}`定义了一个长度为5的数组`{1, 2, 3, 0, 0}`- `int d[10] = {0}` 将数组全部初始化为0:::dangerJava的数组有默认初始化,Java中new出来的都在堆中<br />C++的数组如果定义在函数内,则没有默认初始化<br />C++函数内的变量,包括数组都在**栈中,只有定义在外部才在堆中,且包含初始化。**:::高维数组定义:<br />`int a[10][12]`<br />高维数组初始化:- `int a[3][4] = {{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}}`快速初始化<br />`memset(a, 0, sizeof a)`含义是将从a开始的长度为`sizeof a`字节的空间初始化为0。`sizeof`位于`cstring`库中。<br />拷贝<br />`memcpy(b, a, sizeof a)`含义是将a数组整体复制到b数组。注意是**按字节顺序**赋值。<a name="UWHYr"></a>## 0x06 字符串字符数组:<br />字符串就是字符数组加上结束符'\0'<br />可以使用字符串来初始化字符数组,但要注意每个字符串的结尾会暗含一个'\0',因此字符数组的长度至少比字符串长度大1<br />合法的字符数组初始化:- `char a1[] = {'C', '+', '+'}`- `char a2[] = {'C', '+', '+', '\0'}`- `char a3[] = "C++"`非法初始化:`char a4[3] = "C++"`字符数组当字符串输入:- `scanf("%s", a1)`- `cin >> a2`- `cin >> a3 + 1`:::success输入字符串时,碰到回车或空格就会停止:::问题:如何读入一行?<br />`fgets(a, 100, stdin)`表示从标准输入中读取不超过100个字符的一行数据到字符数组`a`中。**会读取末尾的回车,如果有的话**。<br />`cin.getline(a, 100)`表示从标准输入中读取不超过100个字符的一行数据到字符数组`a`中。**不会读取末尾的回车**。字符数组当字符串输出:- `cout << a1 << endl`会得到`C++`- `printf("%s\n", a2)`会得到`C++`- `puts(a2)`会得到`C++`,参数必须是字符数组。- `cout << a2 + 1 << endl`会得到`++`:::success如果字符数组没有`\0`,不能按照字符串输出<br />输出碰到回车或空格,原样输出,直至遇到`\0`:::常用库函数:| int strlen(char[] s) | 参数:字符数组<br />返回值:字符数组中存储的字符串的长度(不包括'\\0') | `cstring`头文件中 || --- | --- | --- || int strcmp(char[] a, char[] b) | 参数:两个字符数组<br />返回值:0, 1, -1分别表示a == b, a > b, a < b | `cstring`头文件中 || void strcpy(char[] b, char[] a) | 参数:两个字符数组<br />作用:将a复制给b | `cstring`头文件中 |标准字符串:<br />可变长,可修改的字符序列,比字符数组更好用。需引入头文件`string`初始化:- `string s1`定义一个空字符串- `string s2 = s1`,将`s1`拷贝到`s2`- `string s3 = "zdkk"`,用字符串字面值定义- `string s4(4, 'k')`定义一个字符串`s4 = "kkkk"`- `string s5 ("12345", 1, 3)`定义一个字符串`s5 = "234"`(`1, 3`表示从下标1开始连续3个字符):::dangerstring s = 'k' // 非法<br />string s;<br />s = 'k' // 合法,很神奇:::输入:<br />不能用`scanf()`<br />正确方式:`cin >> s`<br />`getline(cin, s)`表示读一行到字符串`s`中,**不会读取末尾的回车**。输出:- 可以用`printf`,需要调用函数。`printf("%s\n", s.c_str())``s.c_str()`返回字符串`s`的首字符地址。- `puts(s.cstr())`- `cout << s << endl`常用函数- `s.empty()`如果返回0,说明不为空。- `s.length(), s.size()`返回字符串长度- 字符串比较,直接用`==`即可,运算符重载- 字符串拼接,`s1 += s2, s1.append(s2)`- 遍历字符串,`for (auto &c : s)`- 插入字符串,`s.insert(3, s2)`在下标3处插入s2- 找子串,`s.substr(1, 3), s.substr(1)`,前者是从1开始的长度为3的子串,后者是从1开始的直至末尾的子串- 删除某段子串,`s.erase(1, 3)`表示删除从下标1开始的长度为3的子串。- 查看最后一个字符,`s.back()`- 删除最后一个字符,`s.pop_back()`- 字符串查找,`s.find(s2, 0)`从s串下标0的地方开始,查找s2的位置,如果不存在返回`string::npos`- 字符串反转,`reverse(s.begin(), s.end())`:::danger字符串拼接必须保证有一方为字符串变量,另一方可以是字符串变量,字符串字面量或者字符<br />s += 'k' // 合法<br />s.append('k') // 非法,很神奇:::<a name="eJeG8"></a>## 0x07 函数C++的函数需要函数声明和函数定义<br />在函数内部可以使用静态变量`static int a = 0`,在多次调用时只会被初始化一次,等价于只能在函数内部使用的全局变量<br />函数参数可以有默认值`int foo(int a, int b = 10, int c = 15)`<br />数组作为参数传入,用`sizeof`测其长度,其实得到的结果是指针的大小<br />数组作为参数传入,除了第一维外,都需要明确指明大小<a name="SEUuQ"></a>## 0x08 类与结构体类中的变量和函数被统一称为类的成员变量。<br />`private`后面的内容是私有成员变量,在类的外部不能访问;<br />`public`后面的内容是公有成员变量,在类的外部可以访问。```cpp#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;class Person {private:int age, height;double money;string books[100];public:string name;void say() {cout << "I'm" << name << endl;}int get_age() {return age;}int get_money() {return money;}void add_money(double x) {money += x;}};int main() {Person c;c.name = "zdkk";c.add_money(10000);cout << c.get_age() << " " << c.get_money() << endl;return 0;}
类与结构体定义的唯一区别在于类中不写作用域,默认是private,而结构体中默认为public
类中的变量类似于局部变量,也没有默认初始化。
// 类与结构体的构造函数与初始化#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;struct Person {int age, height;double money;Person() {};// Person(int _age, int _height, int _money) {// age = _age;// height = _height;// money = _money;// }Person(int _age, int _height, int _money) : age(_age), height(_height), money(_money){}};int main() {Person p;Person c1(18, 180, 100);Person c2 = {5, 100, 200};Person c3 = Person(15, 150, 1000);cout << c1.money << endl;return 0;}
0x09 指针和引用
指针指向存放变量的值的地址。因此我们可以通过指针来修改变量的值。
#include <iostream>using namespace std;int main() {int a = 10;int *p = &a, b = 20;cout << p << endl;}
数组名是一种特殊的指针,指向数组开始地址
#include <iostream>using namespace std;int main() {char c;int a[5] = {1, 2, 3, 4, 5};cout << (void *)&c << endl;cout << a << endl;cout << (void*)&a[0] << endl;cout << (void*)&a[1] << endl;cout << (void*)&a[2] << endl;cout << (void*)&a[3] << endl;cout << (void*)&a[4] << endl;}
指针支持的运算
#include <iostream>using namespace std;int main() {char c;int a[5] = {1, 2, 3, 4, 5};int *p = a;cout << *p << endl;cout << *(p + 1) << endl;cout << *(a + 2) << endl;cout << p[3] << endl;cout << p[10] << endl; // 出大问题,这里居然不报越界,直接输出不确定值}
引用和指针类似,相当于给变量起了个别名。
#include <iostream>using namespace std;int main() {char c;int a = 1;int &p = a;p = 10;cout << a << endl;}
链表
#include <iostream>using namespace std;struct Node {int val;Node* next;Node(int _val) : val(_val), next(NULL) {}};int main() {Node node = Node(1); // 这种写法返回的是Node对象cout << node.val << endl;Node *p = new Node(2); // 这种写法返回的是Node对象的引用cout << p->val << endl;}
