(1) 第一行输入两个整数M,N;接下来M行分别输入2个数,最后一行输入N个数(由于输入行数,个数都确定,用循环很好处理)
(2)循环输入多行
while(cin>>m>>n){
}
while((scanf("%d",&arr[i])!=EOF) && getchar() !='\n'){
}
(3)输入一行数字,数字间以空格分隔
istringstream类中构造字符串流时,空格会成为字符串参数的内部分界;
istringstream 可用于string与各种类型的转换途径
#include
int main(){
string str;
while(getline(cin,str)){
vector num;
int temp;
istringstream iss(str);
while(iss>>tmp){
num.push_back(tmp);
}
}
}
参考:C++ stringstream介绍,使用方法与例子
(4)stringstream的用法
string str1="hello, world!";
istringstream iss;
iss.str(str1); // 将string 类型的str1复制给iss, 返回void
string s;
while(iss>>s){
cout<
(5)输出精度
#include
cout << fixed << setprecision(5) << f << endl;
参考资料:
unsigned int a = 10;
int b = -19;
cout<< a+b <
参考:
不同类型的数据进行运算
C语言不同数据类型间的混合运算+常见数据类型
C语言中数据类型的自动类型转换
C/C++ 内存管理与内存对齐
如果异常被抛出,应满足:
参考资料:
C函数之memcpy()函数用法
#include
#include
#include
using namespace std;
int main(){
srand((int)time(0));
for(int i=0;i<10;++i)
cout<
double a=123.456;
cout<
作用:由于在同一个作用域内,一个名字只能表示一个实例,如果在同一个作用域定义了两个相同名字的变量,就会编译报错。
使用namespace,可以在不同的namespace内定义相同名字的变量,使用变量时注意需要用 namespace_name::val_name 引用变量。
类和函数可以在命名空间内创建,也可以在命名空间内声明,在命名空间外定义,定义时需要引用namespace_name,如下所示
namespace ns
{
// Only declaring class here
class geek;
}
// Defining class outside
class ns::geek
{
public:
void display()
{
cout << "ns::geek::display()\n";
}
};
// Creating a namespace
namespace ns
{
void display();
class geek
{
public:
void display();
};
}
// Defining methods of namespace
void ns::geek::display()
{
cout << "ns::geek::display()\n";
}
void ns::display()
{
cout << "ns::display()\n";
}
匿名命名空间(unnamed namespace):仅在当前文件可访问,可作为声明静态变量的一种替代
命名空间是可嵌套的,引用变量时注意要按层级引用命名空间,例如 out::in::val
别名
namespace alias = name1::name2::name3
参考:
[1] namespace1
[2] namespace2
参考:用最好的方法去理解const int*, int const*以及int *const
参考:
C++是如何调用C接口的?
C++中extern “C”含义深层探索
int m, n;
cin>>m>>n;
int** p = new int*[m];
for(int i=0;i
参考:
[1] std::nothrow
char buffer[1024]={0}; // 先分配一块内存区域
int* p= new (buffer) int[5]; // 在预分配的内存区域上创建对象。
C++ new限定区域分配内存
// 1、修饰由指针指向的对象,表明数据是const或volatile
const char* cp;
volatile char* vp;
// 2、修饰指针,表明指针是const或volatile
char* const cp;
char* volatile vp;
// 注意某些编译器不支持static成员在声明式上获得初始值,此时可以在类外定义时初始化
class A{
private:
static const int Num=5; // 声明常量
int scores[Num]; // 使用该常量
};
const int A::Num; // 类外定义
class B{
private:
enum{Num=5};
int scores[Num];
};
#define CALL_WITH_MAX f((a)>(b)?(a):(b))
// 可以用inline替换
template
inline void callWithMax(const T& a, const T& b){
f(a>b?a:b);
}
class A{
};
class B: public A{
};
A* pA;
B* pB;
pA = pB; // 正确
pB = pA; // 编译错误, C++ 不允许将基类指针隐含转换为派生类指针,不允许非公有继承的隐含转换。
注意:
(为什么要进行运行时类型安全检查?我们知道static_cast也能将基类指针转换为派生类,这时用派生类指针去调用一个只存在于派生类的函数时,编译期不会产生问题,但是会导致运行时错误,因为该指针实际指向基类对象,而基类不包含该函数。)
注意:只能用去去除指针或引用的常量性,不能用于变量。
参考:
C++强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast
C++ 四种强制类型转换
vector > p(m,vector(n));
#include
queue queue1; // 创建队列
queue1.push(x); // 入栈,将x添加到队列的末尾
queue1.pop(); // 出栈,无返回值
queue1.front(); // 访问队首元素
queue1.back(); // 访问队尾元素
queue1.empty(); // 当队列为空,返回true
queue1.size();
//下面两种优先队列的定义是等价的
priority_queue q;
priority_queue,less >;//后面有一个空格
// map 默认按键值从小到大排序
map > myMap;
参考:
c++ map自定义排序
A a;
A b=a; // 定义对象时用已经存在的类对象去初始化,调用拷贝构造函数,与 A b(a) 相同
A c;
c = a; // 将已存在的对象a赋值给已存在的对象c,调用赋值函数
class A{
public:
A() { pBuffer=NULL; nSize=0; } // 构造函数
~A() { delete pBuffer; } // 析构函数
A( const A& obj) {
nSize = obj.nSize;
pBuffer = new char[nSize]; // 开辟新的内存空间
memcpy(pBuffer, obj.pBuffer, nSize*sizeof(char)); // void *memcpy(void*dest, const void *src, size_t n); 由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内,返回一个指向目标内存空间的指针。头文件#include
}
A& operator = (const A& obj){
// if(this==&obj) return *this; // 判断是否为同一对象。
nSize = obj.nSize;
char* tmp = new char[nSize];
memcpy(tmp, obj.pBuffer, nSize*sizeof(char));
delete[] pBuffer; // 删除原有内容
pBuffer=tmp; // 建立新指向
return *this;
}
// 另一种方法:先创建一个临时对象
A& operator = (const A& obj){
if(this!=&obj){
A tmpA(obj);
char* tmp=pBuffer;
pBuffer=tmpA.pBuffer;
tmpA.pBuffer=tmp;
}
return *this;
}
void Init( int n ){
pBuffer = new char[n];
nSize = n;
}
private:
char* pBuffer;
int size;
};
参考:
C++ 拷贝构造函数和赋值构造函数
默认是私有继承。
大多数时候using 被用来指定命名空间:using namespace std;
C++11中提出通过using指定别名,就是这里用到的:using Counter = unordered_map
C++11中引入的auto主要有两种用途: 自动类型推断和返回值占位。参考【C++11】新特性——auto的使用。
可以使用*, &, const 来修饰auto;
auto k=5;
auto c = 'A';
auto s("hello");
auto* pK = new auto(k);
const auto n=6;
// 一些注意事项:
(1) 如果初始化表达式是引用,则去除引用语义
int a = 10;
int& b = a;
auto c = b; // c的类型为int, 去除引用
auto& d = b; // 此时c的类型为int&
c=100; // a=10
d=100; // a=100
(2) 如果初始化表达式是const 或者 volatile,则去除引用语义
const int a1 = 10;
auto b1 = a1; // b1 为 int 类型 而非 const int
const auto c1 = a1; // c1 为 const int
b1 = 100; // 合法
c1 = 100; // 非法
(3) 如果auto 加上&, 则不去除const 语义
const int a2 = 10;
auto& b2 = a2; // b2 类型为 const int
b2 = 10; // 非法
(4) 初始化表达式为数组时, 自动推断为指针
int a[3] = {1,2,3};
auto b3 = a; // b3 为int* 类型
(5) 若初始化表达式为数组且auto加上&,则推导类型为数组类型
int a[3] = {1,2,3};
auto& b = a; // b 为 int [3] 类型
(6) 函数或者模板参数不能声明为 auto
(7) auto只是一个占位符,不是一个真正的类型,不能使用sizeof
cout << sizeof(auto) << endl; // 错误
cout << typeid(auto).name() << endl; // 错误
(8) 使用auto声明的变量必须初始化;
auto a; // 错误
auto int a = 11; // 错误,C++11中已删除auto临时变量的语义
参考:https://www.cnblogs.com/QG-whz/p/4951177.html
c++11引入基于范围的for循环。使用条件:迭代范围确定;迭代的对象要实现++和==操作。参考内联函数、const、auto(C++11)、基于范围for循环(C++11)和nullptr(C++11。
这里用for(auto& a:b)的方式访问unordered_map
0829BIGO视频面
是一种智能指针。采用引用计数的机制,若对象多了一个智能指针指向它,则引用计数加1,若一个指向该对象的智能指针被销毁,引用计数减1。一旦某个对象的引用计数为0,则该对象会被自动删除。
shared_ptr原理是用px来记录指针,用 ∗ p n *pn ∗pn来引用计数,当一个shared_ptr对象达到作用域时,不会释放资源,只有当 ∗ p n *pn ∗pn变为0,才会释放指针指向资源。 进行拷贝构造时,将引用计数加1,并将pn 和 px的值复制过去。
shared_ptr类的构造函数加了explicit 关键字,因此不能进行隐含转换
比如有构造函数 A(int s): data(s){}; 有A* b(3); 则这样写是错误的 shared_ptr c=b; // 即不能将纯指针赋值给shared_ptr,不允许隐含转换
// 头文件
#include
// shared_ptr 三种初始化方法
(1)指向堆上申请的空间
int* a = new int(100);
std::shared_ptr ptr(a);
(2)make_shared
std::shared_ptr ptr1 = std::make_shared(15);
(3)拷贝初始化
std::shared_ptr ptr2(ptr1);
std::shared_ptr ptr3=ptr1;
参考: C++之shared_ptr总结
// 注意事项
(1) 智能指针不能直接赋值(禁止纯指针给智能指针赋值或者拷贝构造)
// 不允许用一个纯指针给一个智能指针赋值或者copy构造,只能使用智能指针给另一个智能指针赋值或者copy构造。
// 这是因为shared_ptr的构造函数加了explicit 关键字,不允许隐含转换。且其拷贝构造函数以及赋值重载函数参数都是 const shared_ptr& 类型
std::shared_ptr ptr2 = new int(5); // 错误
int* a = new int(2);
shared_ptr b=a; // 错误
b = a; // 错误
(2) 不要用栈上的指针初始化shared_ptr , 因为栈中的对象离开作用域本身就会析构一次
(3) 不要用两个智能指针指向同一个内存空间
int* a=new int(2);
shared_ptr sp(a);
shared_ptr sp1(a); // 错误
// 当构造sp的时候,sp.px 指向 *a, *(sp.pn)=1(即引用计数为1)
// 同样在构造sp1的时候,sp1.px指向*a, *(sp1.pn)=1(引用计数也为1)
// 因此sp到达作用域的时候, *(sp.pn)为0,就会释放内存;sp1再达到作用域的时候会再释放一次内存