-
swap用于交换两个输入的值 swap(a,b);
-
三元表达式从最外面的括号开始判断
-
-
setiosflags常用的标志位有:std::ios::showpoint: 即使小数部分为0,也显示小数点。std::ios::showpos: 显示正数的正号。std::ios::skipws: 跳过输入流中的空白字符。std::ios::uppercase: 在输出科学计数法时,使用大写字母(E 而不是 e)。std::ios::fixed: 使用定点表示法显示浮点数,而不是科学计数法。std::ios::scientific: 使用科学计数法显示浮点数。 -
判断多区间多用switch,如果比较少的话会用三元表达式
-
在case中,可以用x ... y 表示范围在[x,y]的值,两边都是闭区间
-
atol是 C++ 标准库中的一个函数,用于将字符串转换为长整型(long)数值。这个函数位于<cstdlib>或<stdlib.h>头文件中。其原型如下:
long atol(const char *str);
在C++中,string(10, '1')是一个构造std::string对象的表达式,它创建了一个包含10个字符'1'的字符串。这不是一个函数,而是一个构造函数调用,用于初始化一个std::string对象。
std::string是C++标准库中的一个类,用于表示和处理字符串。当你使用string(10, '1')时,实际上是在调用std::string类的构造函数,创建了一个含有10个字符'1'的字符串对象。
接下来,.c_str()是一个std::string类的成员函数,它的作用是将std::string对象转换为一个以空字符('\0')结尾的C风格字符串。C风格字符串是一个字符数组,它以一个特殊的空字符作为字符串的结束标志。这种字符串格式在C语言和C++中被广泛使用,尤其是在需要与C语言兼容的接口时。
所以,string(10, '1').c_str()这个表达式的意思是:
- 使用
std::string的构造函数创建一个包含10个字符'1'的字符串对象。 - 调用这个字符串对象的
.c_str()成员函数,将std::string对象转换为C风格字符串。
这样,你就可以使用这个C风格字符串作为参数传递给那些需要C风格字符串的函数,例如atol。
- cout<<fixed<<setprecision(1)<<dist-h<<" "<<h<<endl;这句是1.
fixed:这是流操纵符,用于设置浮点数的输出格式为固定小数点表示法,而不是科学计数法。
setprecision(1):这也是一个流操纵符,用于设置小数点后的位数。在这个例子中,它将小数点后的位数设置为1位。
getline是 C++ 标准库中的一个函数,用于从输入流中读取一行文本直到遇到换行符\n或输入结束。这个函数通常与std::string类型一起使用,来获取用户输入的一行文本。
函数的原型如下:
istream& getline(istream& is, string& str);
is是输入流的引用,可以是std::cin、std::ifstream或任何其他istream对象。str是一个std::string对象的引用,用于存储读取的文本。
getline 函数会读取输入流,直到遇到换行符,并将读取的文本存储在 str 中。换行符本身不会被存储在 str 中。
- C++11里面的for (const auto &item: arr)是如何工作的
假设用户输入了以下字符串:
input: "apple"
第一个循环:遍历字符串 s
在第一个循环中,我们遍历输入的字符串 s。对于上面的输入,循环将依次处理每个字符:
item是'a'item是'p'item是'p'item是'l'item是'e'
对于每个字符 item,我们执行 arr[item - 'a']++。这个表达式做了什么?它将字符转换为一个数字,方法是从字符的ASCII值中减去 'a' 的ASCII值。这样,字符 'a' 会映射到索引 0,'b' 映射到 1,依此类推。然后,我们增加数组 arr 中相应索引的值。
- 对于
'a',arr[0]增加 1。 - 对于
'p',arr[15]增加 1(因为'p' - 'a'等于 15)。 - 再次遇到
'p',arr[15]再次增加 1。 - 对于
'l',arr[11]增加 1。 - 对于
'e',arr[4]增加 1。
第二个循环:遍历数组 arr
在第二个循环中,我们遍历数组 arr。数组 arr 的每个元素都对应一个字母出现的次数。在我们的例子中,数组 arr 将如下所示:
arr[0]= 1 ('a' 出现 1 次)arr[15]= 2 ('p' 出现 2 次)arr[11]= 1 ('l' 出现 1 次)arr[4]= 1 ('e' 出现 1 次)- 其他索引的值都是 0,因为没有其他字母出现。
循环将依次打印数组 arr 中的每个值,后面跟着一个空格:
- 打印
arr[0](1) - 打印空格
- 打印
arr[1](0) - ...
- 打印
arr[15](2) - 打印空格
- 打印
arr[16](0) - ...
- 打印
arr[25](0)
输出结果 最终,程序将输出以下内容,表示每个字母出现的次数:
1 0 2 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
这个输出表示 'a' 出现了 1 次,'p' 出现了 2 次,'l' 和 'e' 各出现了 1 次,其他字母没有出现。每个数字后面都有一个空格,除了最后一个数字。
int arr[3]{};
for (const auto &item: s) { arr[item-'a']++; }
for (const auto &item: arr) { cout<<item<<' '; }
- //新建数组 int* p=new int[n];
在上述代码中,使用 int* p = new int[n]; 来创建一个动态数组,这里的 new 关键字是C++中用于动态内存分配的操作符。使用指针 p 来引用这个动态分配的数组,有以下几个原因:
- 动态大小:
new允许在运行时指定数组的大小,这使得程序更加灵活。用户输入的n决定了数组的大小,而不是在编译时就固定。 - 内存分配:
new操作符在堆上分配内存,而不是在栈上。这意味着可以使用比栈上更大的内存块,并且内存的使用不会受到函数调用栈大小的限制。 - 指针的使用:在C++中,动态分配的内存需要通过指针来访问。指针提供了一种方式来间接访问内存地址,这在需要操作大块数据或者实现某些数据结构(如链表、树等)时非常有用。
- 内存管理:使用
new分配的内存需要显式地使用delete来释放。这是C++中手动内存管理的一部分,允许程序员精确控制内存的生命周期,避免内存泄漏。 - 数组操作:指针允许对数组进行操作,如通过索引访问元素。在上述代码中,
p[i]就是使用指针来访问数组的第i个元素。 - 通用性:指针提供了一种通用的方式来访问不同类型的数据结构,不仅限于数组。它们可以用于实现更复杂的数据结构和算法。
二维数组
在这段 C++ 代码中,二维数组是通过指针数组来实现的。具体来说,int **arr 定义了一个指向整型指针的指针,它用来指向一个整型指针数组,每个整型指针又指向一个整型数组。下面是代码中创建和使用二维数组的步骤:
-
int **arr = new int*[n];这行代码分配了一个指针数组,每个指针指向一个大小为n的整型数组。 -
for(int i = 0; i < n; i++) { arr[i] = new int[n]; }这个循环为每个指针分配了一个大小为n的整型数组。 -
接下来的嵌套循环
for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { arr[i][j] = i + j; } }用于初始化这个二维数组,其中arr[i][j]表示二维数组的第i行第j列的元素。 -
打印二维数组的循环
for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { cout << arr[i][j] << " "; } cout << endl; }用于输出数组中的每个元素。 -
最后,释放二维数组内存的循环
for(int i = 0; i < n; i++) { delete[] arr[i]; }用于释放每个指针指向的整型数组的内存。 -
arr = NULL;将指针数组的指针设置为NULL,表示它不再指向任何内存,这是一个好习惯,但在这个特定情况下不是必需的,因为程序结束时所有的动态分配的内存都会被自动释放。
注意:在实际使用中,通常建议使用 std::vector 或者数组的数组(即数组的数组)来避免手动管理内存,这样可以减少内存泄漏的风险。
- 字符相减默认用的是ASCII表中的值相减
- cin.getline 得到的是字符数组,不是字符串,最后结尾还有一个\0
- 不死神兔问题是斐波那契数列问题
- 引用符号是&,也是取地址符
- 不加地址符:传递的是变量的值,
swap交换的是这些值的副本,原始变量的值不会被改变。 - 加了地址符:传递的是变量的引用,
swap交换的是这些引用所指向的内存位置的值,原始变量的值会被交换。
深拷贝(构造函数)
Person(const Person& p){ //拷贝构造函数
this->name = new char[strlen(p.name) + 1]; //设置name字符数组的长度
strcpy(this->name, p.name); //拷贝name数组
this->age = p.age; }这段代码是什么意思为什么要这么做
这段代码定义了一个拷贝构造函数,它是一个特殊的构造函数,用于初始化一个对象作为另一个对象的副本。下面是代码的逐行解释和为什么要这么做的原因:
Person(const Person& p):这是拷贝构造函数的声明。它接受一个Person类型的引用作为参数,这个引用是对另一个Person对象的引用。this->name = new char[strlen(p.name) + 1];:这行代码使用new操作符动态分配内存,以便存储拷贝对象的名字。strlen(p.name)计算传入对象p的名字长度,+ 1是为了存储字符串的结束字符\0。strcpy(this->name, p.name);:使用strcpy函数将传入对象p的名字复制到新分配的内存中。strcpy是一个C语言标准库函数,用于复制C风格的字符串。this->age = p.age;:将传入对象p的年龄直接赋值给当前对象的age成员。
拷贝构造函数的必要性:
- 深拷贝:当类的成员变量包括指针指向动态分配的内存时(如本例中的
name),拷贝构造函数需要进行深拷贝,即分配新的内存并复制内容,以避免两个对象共享同一块内存。如果不这样做,原始对象的销毁将导致内存泄漏。 - 对象复制:在某些情况下,需要复制对象,例如函数按值传递对象、返回对象或将对象作为参数传递给函数时。拷贝构造函数允许这些操作安全地进行,而不会意外地修改原始对象。
- 默认拷贝构造函数:如果没有显式定义拷贝构造函数,编译器会生成一个默认的拷贝构造函数,它通常只是简单地复制每个成员变量的值。但是,如果类中有指针成员,这可能导致浅拷贝问题,因此显式定义拷贝构造函数可以确保正确的深拷贝行为。
- 一致性:通过自定义拷贝构造函数,可以确保对象的复制行为符合预期,特别是在涉及到资源管理(如内存、文件句柄等)时。
- 异常安全:自定义的拷贝构造函数可以在复制过程中处理异常,确保即使在复制过程中发生错误,对象的状态也是一致的。
在本例中,拷贝构造函数确保了当创建一个Person对象的副本时,name字符串被正确地复制到新的内存位置,而age成员则直接赋值。这样可以保证新对象和原始对象在内存中是独立的,避免了潜在的内存问题。
-
友元函数,把函数的声明放在类的里面同时在前面加上friend关键字,友元函数虽然不是类的成员函数,但是可以访问类的私有数据
-
虚函数(Virtual Functions) :
-
基类中的虚函数可以在派生类中被覆盖。当通过基类的指针或引用调用虚函数时,将调用对象实际类型的函数版本,而不是基类的版本
STL迭代器
- set/map
- isalpha
- upper_bound
- 导入map数据结构用insert
- it = ma.find(x);//查找map中是否有x键的元素,有则返回该元素位置,没有则返回map.end()
make_pair('a', 1)创建了一个pair对象,其包含字符'a'和整数1,然后这个pair被插入到myMap中