您的位置:首页 > 编程语言 > C语言/C++

C++学习笔记

2011-12-13 10:54 239 查看
std就是C++的标准库 就是传说中的STL standard template libary

其中的iostream string vector等都是STL中定义的

标准库中的用<>来include 自己写的用" "引用

.是成员操作符 对象名.类函数名

::是作用域操作符 命名空间::类

想一直让输入值:while(cin>>value)

变量命名习惯:

变量都用小写命名 需要多个单词解释的时候用 _ 或者后面一个词第一个字母大写 textSize或者 text_size

初始化的两种方式

复制初始化:int i=1024;

直接初始化: int i(1024);

内置类型变量是否自动初始化决定于所在的位置:

如果在函数体外定义,默认初始化为0

如果在函数体内定义,不会自动初始化

extern

非const的变量默认都是extern,即可以被外部文件通过extern int i来调用。

而const的常量要在外部调用必须在本文件中显示声明extern const PI;才可以被外部调用

typedef

typedef double price; //就是给double类型起一个别名price

引用&

int x=5;

int &a=x; //引用就是把新的变量指向引用变量,之后对a的所有操作都跟直接对x操作一样

枚举用法

enum direction{north=1,south,east,west};

direction d1=north;

direction d2=2;

类的声明

class Sales_item

{

public:

...

private:

std::string isbn;

unsigned sales;

}; //这里要加分号 ★!!!★

类的数据成员只能通过构造函数进行初始化,不能直接初始化 ★!!!★

定义类在一个头文件中,被需要的文件引用

因为要被多个文件引用,所以注意不应该含有 变量或函数的 定义 可以有声明

头文件保护符避免了头文件在一个文件中多次被引用

#ifndef SALESITEM_H

#define SALESITEM_H

写类定义什么的

#endif

友元类

允许对其非公有成员访问授予给一个函数或者类。

friend开头,只能在类内部声明

friend class Window_mgr;

friend Window_mgr& Window_mgr::relocate(Window_mgr::index.Window_mgr::index,Screen&);

system("pause") 需要引用 cstdlib

引用命名空间时候可以这样using std::string;using std::cout;等

getline来读取一行

string line;

while(getline(cin,line))

string s;

s.zise()返回的是一个string::size_type类型的,不要把size返回值赋给一个int变量

s[i] 定义索引来取的时候i最好也是size_type的类型

头文件引用时候尽量用#include <cmath> 而不是<math.h>

#include <vector>

vector是一个类模板,使用模板可以编写一个类定义或函数定义,而用于多个不同的类型

vector<int> a;vector<myClass> b;

vector不是一个数据类型 vector<int> 是一个数据类型

几种初始化:

vector<Type> v1; //默认v1为空

vector<Type> v2(v1);

vector<Type> v3(n,i); //包含n个值为i的元素

vector<Type> v4(n);

v1.push_back(x);

v1.insert(v1.begin()+2,5);

v1.erase(v1.begin()+1,v1.begin()+3);//删除v1中第2个到第4个元素

v1.clear();//清空

v1.empty();//是不是空的?

v.size();

reverse(v1.begin(),v1.end());

vector操作效率较高的是先定义一个空的vector然后再动态的添加元素

不进行值的初始化 vector会调用默认的构造函数初始化(除非没有默认构造函数,只有自定义的构造函数,此时必须提供元素的个数及初值)

size_type的类型是vector<int> 而不是vector 所以定义时 vector<int>::size_type

C++程序员习惯在写for时用 != 而不是 <

通过下表操作对vector里的元素赋值,不会添加出新的元素(数量不会加)

迭代器对所有容器都支持,但下标操作不是所有容器都支持

各种容器都定义了 各种容器 自己的 iterator类型

vector<int> ivec;

vector<int>::iterator iter=ivec.begin(); //begin()是一个函数,如果容器不为空,返回第一个值

end()也是一个函数,返回最后一个值的下一个,即end()指向一个不存在的元素,如果vector空,end和begin返回的迭代器相同,只是起一个哨兵的作用,代表已经处理完了所有的vector数据

*iter=0; 此时*为解引用操作符 *iter代表里面某个下标的值 *iter++代表往后渐进

vector<int> v1(9,1); //声明一个v1 里面有9个元素 初始都为1

for(vector<int>::iterator iter=v1.begin();iter!=v1.end();iter++) //实现了把每个元素都变成0

*iter=0;

for(vector<int>::const_iterator iter=v1.begin();iter!=v1.end();iter++)//const_iterator类型不会改变值,只能读取

cout<<*iter<<endl;

iter +n -n会产生新的游标

两个游标相减会产生一个difference_type类型的值(这个也是vector里定义的,类似于size_type类型)

vector<int>::iterator mid=v1.begin()+v1.size()/2;

任何改变vector长度的操作都会使已存在的迭代器失效,如push_back之后就不能信赖vector迭代器的值了

bitset类来简化类集的处理

#include <bitset>

using std::bitset;

初始化

bitset<32> bit1; //32个位的bitset对象 记住 灵活定义的初始化只能通过str实现,不能直接=

比如

bitset<16> bit2(0xffff);

string str("1100");

bitset<32> bit3(str); //此时的bit3为 28个0 后面是1100

bitset中的位处理

b.any();//是否存在为1的二进制

b.none();//不存在为1的位?

b.count();//为1的位的个数

b.size();//

b[pos];//

b.test(pos);//为1么?

b.set();//都设置成1

b.set(pos);//某个位置设置成1

b.reset();//都设置成0

b.reset(pos);//某位置成0

b.flip();//反转

b.flip(pos);//某位置反转

b.to_ulong();//转化成一个十进制整数

os<<b;//流入某个输出流

对string对象中字符的处理 #include <cctype>

isalnum(c)//是否为字母或数字

isalpha(c)// 是否为字母

isdigit(c)//是否为数字

islower(c)//是否为小写

isupper(c)

tolower(c)

toupper(c)

string s1;

s1.insert(s1.begin(),'p');

s1.erase(s1.begin(),s1.end());

s1.length();

s1.empty();

s1.replace(2,4,"mygod");//从第二个字符开始(包括),再加上后面4个字符替换为"mygod"

s1.find("ahaha");//在s1中查找ahaha,找到返回第一次出现的下标

reverse(s1.begin(),s1.end());//需要#include <algorithm>

string对象与字符数组互操作

string s;

char ss[100];

scanf("&s",&ss);//string可以直接用字符数组赋值

s=ss;

printf(s.c_str());//用string.c_str()转化为字符数组

按格式分解字符串

string s1,s2,s3;

char sa[100],sb[100],sc[100];

sscanf("abc 123 pc","%s %s %s",sa,sb,sc);

s1=sa;s2=sb;s3=sc;//这样就把一个字符串按格式分解开来

int a,b,c;

sscanf("1 2 3","%d %d %d",&a,&b,&c);//此时是数字格式,要传递指针地址来改变变量的值

int x,y,z;

sscanf("4,5&^1","%d,%d&^%d",&x,&y,&z);//按照字符串的格式来分解

通过字符流转化

把数值转化为string

string convertToString(double x)

{

ostringstream o;

if(o<<x)

return o.str();

return "conversion error";

}

把string转化为数值

double convertFromString(const string &s)

{

istringstream i(s);

double x;

if(i>>x)

return x;

return 0.0;

}

关联容器set

s.insert(5);

s.erase(5);

s.size();

s.find(5);//返回迭代器的位置

#include <set>

int main()

{

set<int> s;//定义一个set

s.insert(8);//插入一个元素

s.insert(1);

s.insert(12);

s.insert(8);//重复插入不生效

set<int> iterator it;

//set<int> reverse_interator rit//反向迭代器

//for(rit=s.rbegin();it!=s.rend();rit++)

for(it=s.begin();it!=s.end();it++)

{

cout<<*it<<" ";

}

cout<<endl;

//s.erase(6);//删除键值为6的元素

return 0;

}

自定义myComp

struct myComp //从大到小

{

myComp()(const int &a,const int &b)

{

if(a!=b)

return a>b;

else

return a>b;

}

};

set<int,myComp>::iterator it;

multiset允许插入重复键值的点

也有erase find方法

map容器的数据元素由一个键值和一个映照数据组成

#include <map>

map<string,float> m;

插入元素

m["JACK"]=90.3;

m["Bomi"]=43.2;

m["Kate"]=23.3;

m.insert(pair<string,float>("Zoe",76.3))

map<string,float>::iterator it;

for(it=m.begin();it!=m.end();it++)

cout<<(*it).first<<":"<<(*it).second;//使用first,second

也可以用rbegin rend来反转

m<string,float>::iterator it=m.find(90.3);//返回指针位置

deque双端队列

#include <deque>

deque<int> d;

d.push_back(5);//从队列后插入,使队列元素值增加

d.push_front(3);//从队列前插入,替代队列前端的树

d.insert(d.begin()+1,7);//在某个位置插入,代替所在元素

deque<int>::iterator it;

deque<int>::reverse_iterator rit;

pop_front();//从头部删除元素

pop_back();//从尾部删除元素

d.erase(d.begin()+1);//删除某个元素

list双向链表

只能对迭代器使用++ --来移动,不能直接+n -n来移动

#include <list>

list<int> l;

l.push_back(5);

l.push_front(6);//都会增加长度

list<int>::iterator it;

it++;

l.insert(it,20);

l.remove(20);//这里是remove

l.erase(it);//删除迭代器上的值

l.pop_front();

l.pop_back();

it=l.find(l.begin(),l.end(),5);//需要声明#include <algorithm>

l.sort();

stack堆栈

#include <stack>

stack<int> s;

s.push(5);

s.pop();

s.top();

s.empty();

s.size();

queue队列

#include <queue>

queue<int> q;

q.push();

q.pop();

q.front();

q.back();

priority_queue最大的元素在最前,也可重载<运算符

pop每次pop最前端,也即是最大的元素

一般只转换bitset的某一个段

string str("1111111000000011001101");

bitset<32> bit4(str,5,4); //这里从str[5] 注意 不是第5个字符开始,往后找4位,即1100

bitset<32> bit5(str,str.size()-4);意味着从开始处取到最后,此处为后四位数1101

对bitset对象的操作

b.any() b中存在置为1的位?存在返回TRUE 不存在返回FALSE

b.none() b中不存在为1的位?不存在返回TRUE 存在返回FALSE

b.count() b中为1的位数

b.size() b的位数

这两个函数返回值的类型是size_t类型,定义在cstddef头文件中,是一个与机器相关的unsigned类型

b[pos] b中的二进制位

b.test(pos) b中pos处的二进制位是否为1

b.set() 全置1 b.set(pos) pos设1

b.reset() 全置0 b.reset(pos) pos设0

b.flip() 全取反 b.flip(pos) pos取反

unsigned long ulong=bit1.to_ulong(); //把位所表示的值转化为 平时见的 值 比如“1111”为15

直接对bitset对象进行cout 得到的是其一位位的1010的排序值

数组 长度是固定的,没有获取其长度的size操作,也不提供push_back操作

只有当性能测试表明使用vector无法达到必要的速度要求时,才使用数组

字符数组

char a[]={'c','+','+'};

char b[]="c++";

char c[]={'c','+','+','\0'};//和上式等价

指针,保存的是一个对象的地址

用*把一个标识符声明为指针

要么修改指针指向的对象,要么修改指针中存储的地址

即 通过指针进行赋值 和 给指针赋值

比如有

string s1("i am a string"); string *sp1=&s1;

如果*sp1="a new string"; 实际上改变了(sp1所指向的对象)s1的值

如果sp1=sp2; 实际上改变了这个指针所引用的对象

指针和引用的区别:

引用&一经初始化就不能改变 int &a=x; 看到a就跟看到x一样

指针string *a=" " a只是后面的一个代理,之后也可以转去代理别的值

若指针直接指向一个数组,则其实是指向了数组的第一个元素 int *ip=array; //int *ip=&array[0];

int *p=&ia[2];

int j=*(p+1) 后者 int j=p[1] 都是代表访问p所在下一个位置的数据

用指针遍历数组

const size_t arr_az=5;

int a[arr_az]={2,3,1,9,5};

for(int *abegin=a,int *aend=abegin+arr_az;abegin!=aend;aend++)

//定义指针指向数组开始第一个元素,再定义一个指针指向最后一个元素后一个位置

*abegin=0;

const double *d; //自以为指向const的指针,不能通过他来改变指向的值

int *const d; //不能指向别的对象的指针

const double *const d; //既不能修改指向对象的值,也不能修改指的方向

#include <string> 跟 #include <cstring> 不是一回事

C风格的字符串使用strlen strcmp strcat等函数进行操作

不要忘记最后必须有一个null,但是strlen返回是不带最后null的数

程序员必须自己保证目标字符串足够大

尽量使用string 避免使用cstring

创建动态的数组

string *psa=new string
; //不声明名字,指针*psa指向数组第一个元素的位置

用法:

for(int *q=psa;q!=psa+n;q++)

{ ...... }

用完以后释放掉

delete [] *psa; //注意要加[]

用数组来初始化一个vector

需要两边两个指针

const size_t arr_size=6;

int arr[arr_size]={1,4,5,2,3,2};

vector<int> ivec(arr,arr+arr_size); //两端的指针,其中后一个是指被复制的最后一个元素后的地址空间

多维数组

int ia[3][4];

int (*ip)[4]=ia; //这个指针的类型为 维数为4的int数组

ip=ia[2]; //把指针指向ia[2]

用typedef简化

typedef int int_array[4];

int_array *ip=ia;

for(int_array *p=ia;p!=ia+3;++p)

for(int *q=*p;q!=*p+4;q++)

cout<<*q<<endl;

++i的效率比i++要高

箭头操作符:

MyItem a;

MyItem *sp=&a;

则要获取a中的成员时 用a.foo 或者用指针形式 sp->foo; ★!!!★

sizeof() 可以知道一个类型或者对象所占的长度 单位为字节

在循环语句中创建的变量每一次都要经历创建啊和撤销的过程

标准库定义的异常类,在stdexcept头文件中

exception 常见的问题

runtiem_error 运行时错误,仅在运行时才能检测到的错误

range_error 运行时错误,结果超出了有意义的值域

try

{

....

throw runtime_error("Data illegal!!!");

}

catch(runtime_errr)

{

cout<<err.what();

...

}

一些常量

__FILE__ __LINE__ __TIME__ __DATE__

文件的读写

#include <iofstream>

ofstream a("a.txt");//把a绑定为向a.txt文件的输出流

ifstream b("a.txt");//把b绑定为输入a.txt文件的输入流

a<<something; //把something写入a

b>>something; //把b中的值写入something

switch(a)

{

case 1:

case 2:

do something;

break;

case 3:

lalala;

break;

defalt:

blabla;

break;

}

如果只是单纯的为了避免使用复制引用(比如只是为了引用而不需要修改引用参数),把引用参数为const

bool aa(const string &s1,const string &s2)

函数的参数 如果不是&引用 只是对实参的一个副本引用,任何赋值操作不会改变原实参

如果使用指针作为参数,可以改变指针所指向的变量的值

引用形式参数 void swap(&s1,&s2);

//如果数组作为非引用参数,实际上是以指向数组第一个元素的指针为参数

//作为引用,则传递整个数组

static int i;无论在哪里声明 都是全局变量

(inline) //这样可以内联函数

const string &shorterString(....) //解析:返回的类型是一个对string的引用 这个引用指向是不变的,所以有const

this是一个指针 用的时候this->isbn; 但一般不些this也默认是隐士定义

类的构造函数

名字与类名相同,没有返回值

构造函数的初始化列表,函数名冒号后面是对类的一个或多个数据成员指定初值

Sales_item():units_sold(0),revenue(1,5)

{

}

▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲第9章顺序容器▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲

▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲第10章关联容器▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲

▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲第11章泛型算法▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲

类中的成员函数声明

double avg_price() const;//后面的const代表这个函数不改变成员函数

友元 以关键字friend开始,只能在类中出现,友元类可以访问本类的私有成员

▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲第13章复制控制▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲

▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲第14章重载运算符与转换▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲

重载运算符

在类中定义

bool operator==(const Date&a,const Date&b)

{

return a.year()==b.year()&&aa.month()==b.month()&&a.day()==b.day();

}

使用 string名.c_str()转化为c风格字符串

cin除了普通的用法外还可以cin.getline(ch,26)一行获得 cin.get(ch)一个一个获得 其中char ch[256];

'\0'表示字符串的结束符

char(65)可以输出字母

printf("%d%c",amount,str[i]);

scanf();

strcmp(show1,show2) 要求两个参数都为const

show1.compare(show2);不需要为const

控制小数精度

cout.preision(2);

printf("%.2f\n",i);

二维数组int p[10][10]

字符串的长度用length()

vector长度用size()

reverse(xx.begin(),xx.end())
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: