背景:在学校的时候学习了C++并做了两三个大作业,C++还有些印象,这里总结一些C++容易忘记的知识点。欢迎不吝赐教。
C++中*与&的区别
*是取值运算符,对地址使用可以获得地址中储存的数值。 对于指针a,*a表示取a中的值
&是地址运算符,对变量使用可以获得该变量的地址。 对于变量b,&b表示取b的地址
在定义时,* 是一个标识符,声明该变量是一个指针,比如说int *p; 那p就是一个指向int型的指针;在调用时,*p是指针p指向的那个变量,比如说之前有int a=5;int *p=a;那么p的值是a的地址,也就是指针p指向a,*p则等于a的值,即*p=5。
而&,则是引用,比如说有定义int a=5;再定义int b=&a;那么这里的b则引用a的值,即b=5,而再给b赋值:b=10,a的值也会变为10。
int main()
{
int a = 3;
int *b = &a;
cout << "a:" << a << endl; // 输出a:3
cout << "b:" << b << endl; // 输出b:00EFFE28
*b = 10;
cout << "&a:" << &a << endl; // 输出&a:00EFFE28
cout << "b:" << b << endl; // 输出b:00EFFE28
return 0;
}
分析:
b是a的指针,指向a的地址。(也就是a与b相连,只要修改*b的值,a的值也跟着改动)
&变量声明时表示引用,使用时表示取地址。
C++中传递数组给函数和函数返回指向数组的指针
C++ 传数组给一个函数,数组类型自动转换为指针类型,所以传的实际是地址。
C++ 是不允许返回一个完整的数组的。但是,可以通过指定不带索引的数组名来返回一个指向数组的指针。(另外,要注意不能返回局部变量的地址,除非定义局部变量为 static 变量。)
const限定符
1.const与引用
将引用绑定到const上,就叫对常量的引用了。考虑到const的特征,对常量的引用不能用作修改它所绑定的对象。不能用对常量的引用给普通的引用初始化(非常量可以转换成常量,反之不可以)。
const int ci=1024;
const int &r1=ci;//正确,引用及其对应的对象都是常量
int &r2=ci;//c错误,试图让一个非常量引用指向常量引用。注意这两行代码的区别
const int &r2=42;
2.const与指针
把一个指针定义成了不可改变的常量,一个指针能够表示一个对象以及对象的地址,很显然,const指针就可以表示地址本身是常量还是表示的数据是常量,《C++ Primer》中前者叫顶层const,后者叫底层const。
一般而言,指针的类型与其所指对象的类型要一致。但是一个指向常量的指针可以指向一个非常量对象(反之不行),从而间接的改变常量指针的值。例如:
const double pi=3.14;
const double *cptr=π
double dval=3.333;
cptr=&dval;
分析:这里cptr指向的就是dval的地址,*cptr就是3.333了。
但是不能通过cptr改变dval的值,指向常量的指针仅仅要求不能通过当前指针改变对象的值,
但是可以通过其他途径间接的改变。
将*放在const前面是const指针,作用是说明指针是一个常量,其深层含义是地址本身是常量而所指向的值可能被改变了。
int errNumb=0;
int *const curErr=&errNumb;//curErr将一直指向errNumb的地址
int errNumb2=2;
curErr=&errNumb2;//错误,不能再绑定其他值了
malloc 与 new 的区别
a. malloc动态内存分配,unsigned int size 申请size个字节的内存空间,从堆中获得空间。OS有一个记录空闲地址的链表,当OS收到程序的申请时会遍历该链表然后找到第一个空间大于所申请空间的堆节点,然后将该节点从链表中删除,将该节点的空间分配给程序。
1.申请内存后必须检查是否分配成功
2.不再需要申请的内存的时候需要手动释放free为null,避免之后被无用
3.申请和释放应该配对,申请后不释放是内存泄漏,无故释放就是什么都没做,
释放只能一次,释放两次及以上会出现错误
4.虽然malloc函数返回类型是void*,任何类型的指针都可以转成void*,
但最好还是在前面强转类型以避免一些编译器的检查。
b. new 和delete动态创建和释放数组或单个对象,new返回指向新创建对象得到指针,可以通过指针访问对象
c. 区别:
1. new返回指定类型的指针,并且可以自动计算所需大小;
而malloc必须由程序员计算所需字节数,并在返回后强制转换为实际类型的指针
2.malloc只负责内存分配并不进行初始化,所以在新内存中其值是随机的,
除了分配及释放方式的不一样外通过new和malloc得到指针 ,在其它操作上保持一致
3.malloc/free是C++/C语言的标准库函数,new/delete是C++的运算符,
都可以用于动态申请和释放内存
4.对于非内部数据类型的对象而言,mallloc/free无法满足动态对象的要求,
对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,
不能够把执行构造函数和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。
assert关键字
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行。
assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
用法:在函数开始处检验传入参数的合法性。有的地方,assert不能代替条件过滤。assert是用来避免显而易见的错误的,而不是处理异常的。错误和异常是不一样的,错误是不应该出现的,异常是不可避免的。
已放弃使用assert()的原因是,频繁的调用会极大的影响程序的性能,增加额外的开销。在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用。
标准异常
自定义异常
处理在try/catch语句中
构造函数、析构函数
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
#include <iostream>
using namespace std;
class Line {
public:
void setLength( double len );
double getLength( void );
Line(double len); // 这是构造函数
~Line(); // 这是析构函数声明
private:
double length;
};
// 成员函数定义,包括构造函数
Line::Line( double len) {
cout << "Object is being created, length = " << len << endl;
length = len;
}
或者使用初始化列表直接初始化字段
Line::Line( double len): length(len) {
cout << "Object is being created, length = " << len << endl;
}
Line::~Line(void) {
cout << "Object is being deleted" << endl;
}
最大堆最小堆
C++ STL的priority_queue默认最大堆,实现对任意数据类型的最大堆或者最小堆需要在类中定义排序函数。
其它解决:简单数据类型直接使用最大堆实现最小堆:将数据的相反数存入最大堆,取出时复原对应的数据即可。
struct Node {
int value;
int idx;
Node (int v, int i): value(v), idx(i) {}
friend bool operator < (const struct Node &n1, const struct Node &n2) ;
};
inline bool operator < (const struct Node &n1, const struct Node &n2) {
return n1.value < n2.value;
}
priority_queue<Node> pq; // 此时pq为最大堆
---------------------------------------------------------------
如果需要最小堆,则需要如下实现:
struct Node {
int value;
int idx;
Node (int v, int i): value(v), idx(i) {}
friend bool operator > (const struct Node &n1, const struct Node &n2) ;
};
inline bool operator > (const struct Node &n1, const struct Node &n2) {
return n1.value > n2.value;
}
// 此时greater会调用 > 方法来确认Node的顺序,此时pq是最小堆
priority_queue<Node, vector<Node>, greater<Node> > pq;
string与char*, char[]的转换
char * 和char str[]类型可以直接转换为string 类型:
char * chstr;
char arstr[];
string str=chstr;
或者是string str=arstr;可以直接进行赋值。
string 转换为char *:
string直接返回字符串的首指针地址:string.c_str();
string str="Hi Cpp";//转换为char * 类型;
const char * mystr=str.c_str(); //注意要加上const.
获取数组长度
c,c++中没有直接获取数组长度的函数,字符串数组有strlen()方法,其它类型数组需要指定。
数组判空array == nullptr 或者 len == 0;
int len = (sizeof(array) / sizeof(array[0]));
//该方法求字符串数组长度需-1,最后一个字符为结束标志'\0'