C++中易记混知识点总结(长期更新)
2017-09-14 20:45
302 查看
C++中易记混知识点总结(长期更新)
1、const指针和引用
const int &a;//引用对象为const,但实际上只是a一厢情愿为const引用,应用对象可以为普通变量,但a仍不能改变其值(特别注意在函数形参中的使用)。const int *a;//指向常量的指针,和上面常量引用一样是一厢情愿,注意从右向左看,a首先是一个指针,指向一个const int。
int *const a=&cc;//从右往左看,a首先是一个常对象,其次是一个指针,说明是一个常指针,常指针必须初始化,之后便不能改变。引用不是对象,不存在本身是const的引用。
不能将一个指向(引用)常量的指针(引用)赋值给一个普通指针(引用),这样有可能造成所指(引用)对象改变。
2、复杂度数组、函数声明
int *p[10];//从左往右看,首先由[10]看出p是一个数组,再看*可以知道数组中存储的是指向int的指针,可以理解为(int *) p[10],此语句定义的是一个数组。int (*p)[10]=&cc;//先从括号内向外,p前面有*,在定义中一定是指针,所以p是指向数组的指针,数组内容为int类型,此条语句定义的就是一个指针p。
int &p[10];//没有这种写法
int (&p) [10];//数组本身是对象,所以允许定义数组的指针和引用,从内向外看,p前面有&,所以p为引用,是数组的引用。
int *p();//从右往左看,表示函数p返回值是(int*)。
int (*p)();//从内往外,p是一个指针,指向一个函数。
定义一个返回指针且指针指向一个数组的函数有两种方法:
一是使用类型别名
typedef int arrT[10];//arrT是一个类型别名,表示的类型是含有10个整数的数组,等同于using arrT=int[10]
arrT* func(int i);//此函数返回指针,指向一个arrT类型,也就是一个含10个整数的数组。
二是如下
int (*func(int i))[10];//从内向外,func返回一个指针,(*func(int i))解引用为一个数组名,所以此语句定义一个返回指针的函数,指针指向一个int 数组。
int *(&array) [10] =ptrs;//int *ptrs[10],从内向外看,array是一个引用,引用一个数组,数组内容为(int *)类型。此语句定义的是array,所以初始化给的是ptrs。
3、指向数组的指针
int *matrix[10];//定义了一个由十个int指针组成的数组。int (*matrix) [10];//定义了一个指针,指向含有10个整数的数组。
int matrix[] [10];//同上一个,matrix[]==(*matrix)。
4、类模板和模板类一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默认成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。模板类其实是类模板的实例化产物,如vector和initializer_list都是类模板,而vector<int>是一个模板类。函数模板和模板函数区别类似。
5、string的一些小知识
string的size()函数返回值类型为string::size_type,这是一种能保存任意string长度的无符号整数,时常可以定义为auto n=nums.size()。比较两个string对象,==需要长度内容完全一样,如果两个string长度不同,短的string的每个字符都与长string对应位置的字符相同,则短的<长的,如果在对应位置不一致,则比较的是第一个不一致字符的大小。
如:string a="Hello",string b="Hiya",则b>a.
字面值和string对象相加,必须保证加号的一边为string对象,有括号的按优先级来看,如:
string a="abc"
string b=a+", "是正确的
string c="sd"+"sdd"是错误的
string d=(a+"sd")+"se"括号内生成的是string对象
6、string和int的相互转换
有两种方法,一种是采用stringstream,包含在头文件sstream里。stringstream stream;
string s;
int n;
stream<<s;
stream>>n;
第二种是采用C++11的新特性,string to_string(int a),int stoi(string a);
int n=2;
string s=to_string(n);
int a=stoi(s);
7、fstream和sstream
头文件fstream中定义了三个类fstream,ofstream,itstream,分别用来读写文件、写文件、读文件,下面代码实现了从文件中读取字符串,并直接转化为int数据,文件流中默认以空格作为间隔:ifstream FILE;
FILE.open("execute.stdin");
vector<int> nums;
int a;
while(!FILE.eof()){
FILE>>a;
nums.push_back(a);
}FILE文件流从字符串中每次读入一个字符串给a,并根据a的类型直接将类型转化,如果FILE文件读到末尾,则流的状态会变成EOF,此时读写操作都将不成功。
类似的,头文件sstream中定义了三个类stringstream、istringstream、ostringstream,定义一个stringstream对象ss,和一个string a="sadf",利用ss的构造函数,可以用stringstream ss(a),将ss初始化,此时定义一个string temp,可以利用一下代码依次将ss中的string传递给temp:
while(!ss.eof())
ss>>temp;
也可以写成while(ss>>temp)
如果后续需要将temp转化为int,可以考虑定义一个stringstream s2,利用以下代码实现:
int a;
s2<<temp;
s2>>a;此时要注意,由于ss只有一个元素,因此在s2>>a后,s2的状态将被置为eof,不能进行任何读入读出操作,所以如果上述三行代码在循环中实现多次string到int的转化,s2将会在第一次之后失效。解决办法是使用s2.clear(),清除它的EOF状态,同时由于s2的缓存区会逐步增大(不是eof时),为了减少内存消耗,需要每次读取完毕后调用s2.str(""),将s2的缓存清空,上面两句代码都是必不可少的。为了避免上述情况,可以利用stoi和to_string来完成int和string的转化。
8、string的基本操作
string也是顺序容器,所以拥有顺序容器的许多基本操作。同时还有一些特有的操作,如截取、替换、查找。截取:s.substr(pos,n),其中pos表示下标,不是迭代器,n表示截取的数量,返回提取的那一段,如果想删除某一段,可以将截取后的一段重新赋值给原字符串。
替换:s.replace(pos,n,s1),用s1替换s从位置pos开始的n个字符。
查找:s.find(a,pos,n),是从pos开始找目标a,a可以是一个string、char *、char,n是查找位数,可以不要。返回查找到的位置,没有找到返回-1
s.find_first_of、s.find_last_of。
翻转:algorithm头文件中,reverse(s.begin(),s.end()),此函数对其他容器也适用。
9、fstream补充知识
定义一个文件流,同时将它与一个文件关联,fstream("mytext.txt"),该语句默认用in和out模式使用文件,默认情况下,out模式打开文件默认会截断,也就是说out模式下文件内容会被丢弃,阻止其清空文件的方法是显式设置app模式,fstream("mytext.txt",ios::out|ios::app)。ios比fstream高级,可以通用。在使用中最好将读写操作分别用ifstream和ofstream流来操作,这样可以避免文件模式的设置。如果一定要用同一个流,需要控制读、写的标记,当需要写的时候,要利用f.seekp(offset,from)设置写标记,from可以取fstream::end、beg、cur,如果用fstream::end,表示从文件末尾开始读。f.seekg()表示设置读位置,tellp()表示返回写位置,tellg()表示返回读位置。
fstream ii("test.txt",ios::in|ios::out|ios::app);
string k;
ii >> k;
ii.seekp(0,fstream::end);
ii << "111" << endl;上述代码中,test.txt中已有内容,向k中读入后,如果直接再向文件写入,写入会失败,此时需要将写标记移动到文件尾,然后写入成功。
10、关联容器不能采用sort排序
set、map内部采用红黑树,内部存储元素是pair,不是线性存储的。set和map对key进行了排序,而需要对value排序,必须将map转移到线性容器如vector等中,不能使用sort。11、求任意对数的方法
C++中有两个对数log(ln)和log10,对于任意对数可以用上述对数相除得到,但注意用log相除可能会由于四舍五入造成偏差,所以用log10比较好。12、关联容器迭代器用法
由于关联容器不是线性存储,因此其迭代器用法和string、vector等线性容器有所不同。如对于map s,s.begin(),要遍历下一容器只能++s.begin(),不能够s.begin()+1,因此也没有s.begin()+n的方法。13、变量是在堆上还是栈上
一个程序内存分为五类,栈、堆、全局(静态)区、文字常量区、代码区。栈
栈由编译器自动释放,用于存储局部变量,函数参数等,是高地址向低地址扩展的连续内存,一般1M到2M,超出会报overflow。栈上的东西出了作用域会自动回收。如在函数中定义int a[1000][1000]便会超出。
堆
堆是程序员自己分配释放,是用链表连接的从低到高的不连续内存区,灵活度高,容量大,但是不如栈快。用new或malloc动态分配的空间都在堆上。例如char *p=new char[2]
如上述语句在函数中,则指针p本身(一个地址)存储在栈中,而它指向的一段内存则是在堆中,同样由于vector内部采用new,因此vector<int> a(100,0),的对象a本身是在栈中(这个对象肯定包含了一个指向堆中的指针),但是它的内容,100个int则都是在堆中。对于类的对象,有如下例子阐述对象的成员是在堆中还是栈中:
class A{
vector<int> a(100,0);
};
int main(){
A b;
A *c=new A;
}
对象的成员是在堆中或栈中取决于对象本身,如果是在函数中且非动态分配内存,则对象的成员在栈中,在本例中b的成员a在栈中,但是它的100个int是在堆中,这是决定于vector内部,而c指向的对象的成员a在堆中,其100个int也在堆中。
全局变量和static均在静态区
字符串常量等在文字常量区
14、heap操作和priority_queue
heap操作定义在algorithm中,是一个操作容器的函数,priority_queue不是STL标准容器,底层采用了heap算法,而它们保存数据的容器都是vector或deque。heap操作直接对vector进行,将存在vector中的一个完全二叉树(每一层从左到右放入vector中)进行建堆等操作。heap操作有如下几个:
int main () {
int myints[] = {10,20,30,5,15};
std::vector<int> v(myints,myints+5);
std::make_heap (v.begin(),v.end());
std::cout << "initial max heap : " << v.front() << '\n';
std::pop_heap (v.begin(),v.end()); v.pop_back();
std::cout << "max heap after pop : " << v.front() << '\n';
v.push_back(99); std::push_heap (v.begin(),v.end());
std::cout << "max heap after push: " << v.front() << '\n';
std::sort_heap (v.begin(),v.end());
std::cout << "final sorted range :";
for (unsigned i=0; i<v.size(); i++)
std::cout << ' ' << v[i];
std::cout << '\n';
return 0;
}
make_heap(begin,end),函数参数为一个vector或者deque的前后迭代器,默认less模式,也就是第一个元素是在大元素的最大堆。如要采用最小堆,第三个参数为greater<type> (),是重载的().
pop_heap(begin,end),将一个已建堆的vector的第一个元素放到end之前,并将前面元素恢复堆特性,此时最大(最小)元素并没有pop出,需要用vector.pop_back()将元素弹出。
push_heap(begin,end)是对一个刚加入新元素的堆,重建它的堆特性。
sort_heap(begin,end)是多次进行pop_heap操作,最终完成一个排序,最大堆模式下得到的排序为升序。
priority_queue的用法如下:
它除了有queue的一些用法,还有几个特殊用法。
priority<type,container type,compare type> qp;type表示优先队列中元素的类型,可以是自定义类,第二个元素为容器的类别,如vector<type>,第三个是一个比较函数类,默认为less,也就是采用最大堆,最终排序为升序,先出大的元素。如果要用最小优先队列,则需要加上greater<type>,注意这里没有括号,如果type是自定义类,则需要单独写比较类,如下,这里是从队列的角度看的,需要一个递减序列,用最小堆实现。这里重构了一个().
class myCompare{
public:
bool operator()(Node &a,Node &b){
return a.len>b.len;
}
};
pq.empty(),pq.top()取最大(最小)元素,pq.pop(),pq.push()。
15、malloc() free()和new delete的区别
malloc的参数是字节数,必须用sizeof给定类型的大小,且返回void *类型,必须强制转化为相应指针类型,如char *p=(char *) malloc(sizeof(char)*128),这语句分配了128个char的内存,在堆中。而new的用法为char *p=new char[128]。
对于自定义类,new和delete能自动调用类的构造和析构,malloc不行,但C语言只支持malloc
注意不管是new还是malloc,如果指针是局部变量,它就在栈,但是申请的空间是在堆。malloc采用空闲链表机制,延表寻找大小满足所需的内存块,将需要的大小分出,留下剩余的小部分继续在表中,这样最终就会造成表中内内存均是碎块,申请内存失败,返回NULL指针。
free之后是指针所指内存释放,指针并没有,指针是一个变量,只有随函数完毕而销毁。
相关文章推荐
- 日常知识点总结<长期更新>
- c++知识点总结(仅限个人)持续更新。。。。
- c++知识点总结(不时更新)
- 后端c++知识点总结
- STL + c++ + 模板 + 重要思维 + 基础算法+ 经典算法 + 经典实例 + 编程总结+ 心得+ 入门必会 + 知识点汇总。+string +dfs +bfs等重要算法
- java知识点总结,持续更新
- C++及数据结构笔试面试常见知识点总结
- C++知识点总结
- 程序员笔试知识点总结之C++
- C++知识点部分总结
- c++知识点总结(2)
- C++ 有关于函数对象以及谓词部分练习以及知识点的总结
- iphone开发小知识点总结(更新)
- C/C++基础知识点总结
- C++知识点总结(三)
- c++开发中常见bug总结(不定期更新)
- c++知识点总结--new的一些用法
- Java小技能点汇总(一)<日常开发中遇到的一些小知识点-长期更新>
- Oracle知识点总结—子查询与数据更新
- 数学知识点 长期更新.