• C++初级 入门笔记学习(一)


    1,C++Primer初级:
    预处理(E查看)->编译(S查看)->连接
    
    13_枚举:可以尽可能多用枚举,多个const变量,可以用枚举去做;
    
    string name("aaa"); //定义,初始化
    string::size_type size = name.size();  //字符个数,保证可以获得对应的大小,int size = name.size(); 这个不安全
    name.empty() 判断是否为空
    字符串相加,是表示将两个连接起来,但是两个不能都是字符串字面值
    例如 name+name2,但是不能“aa”+“bb”
    ispunct(name[i])判断某个字符是否是标点符号(头文件cctype)
    字符串的输入,不能用cin要用getline,然后用for循环,检查输入的字符串的每一个字符
    
    vector 动态数组,其实是个类类型,一般可以替换到普通的数组。
    常用里面的empty(),vector<int>::size_type, v.size(),和v.push_back();
    vector begin(),返回一个迭代器,vector<int>::iterator iter = v.begin; 迭代器实质上是一个指针,所以可以给该值赋值*iter=9;
    一般用迭代器替代下标,例如用vector<int>::size_type idx=0;
    可以for(vector<int>::iterator i=v.begin();i!=v.end();i++){
        cout <<"迭代器 "<<*i<<endl;//这样可以通过*i获得vector v中的元素;即迭代器是个指针,这比下标取元素简单多了,尽量多使用迭代器方式,少用下标形式取元素
    }
    常迭代器与非常迭代器,区别为,不可以与可以通过迭代你修改数据
    例如 vector<int>::const_iterator i = v.begin(); 常迭代器常用来读取数值,不用常迭代器修改数据;
    
    bitset<32> a(156) 将156按二进制存储,到32位大小空间中。
    a.any(); 判断是否有1,a.none()判断没有一个1,a.count() a有几个1.a.size()获得a的大小;a.set(index) 设置某位为1。或者直接下标写法,a[index]; a.set() 设置所有的为1. reset是变为0;
    
    void*指针,是万能指针,可以指向任意的类型。但是这种指针不能通过其操作对象。
    常指针才能指向常对象;普通指针不行,常指针必须初始化。常指针(常用来传递参数,防止修改参数)可以指向非常对象,这样之后,不能通过指针来修改其对象的值,也不能修改其指向再指向其他的对象。
    举例:
    #typedef string *pstring;
    const pstring cpst; 与string *const cpst1;等同(常指针,指向字符串,必须初始化),与const string *cpst2;不同,指向常字符串指针,不用必须初始化
    int a[]={1, 2, 3, 6, 5, 4}
    int *ip1=a; //指针可以可以看做数组的迭代器。
    int *ip2 = a+4;
    ptrdiff_t a=ip2-ip1;得到地址差。即a=4;相差四个数
    
    引用声明时,必须初始化。指针可以不用
    
    c风格的字符串,必须用结束。
    char a1[] = {'a', 'b', ''};是
    char a2[] = "ab";是
    char a3[] = {'a', 'b'} 不是,只是c风格的字符数组
    const char *a4 = "ab";是
    strlen(a2);计算结果不包括0
    c风格的字符比较,用strcmp;而c++风格的字符串string类型,可以直接比较。字符串string类型可以s1>s2,s1==s2。但是c风格的字符不能a1==a2等操作,这样操作的仅仅是地址。而不是内部的值;
    c风格的字符不能用=做拷贝,必须用strcpy(a1,a2);。strcat(a1,a2);c风格的字符串连接,c++的string类型的连接直接用+号,
    标准库中strcmp,strcpy,strcat等都比较危险。一般使用带n的方法,例如strncmp,strncpy,strncat等,strncpy(a1,a2,2);n制定了拷贝的大小。不然很多黑客可以利用这些漏洞,可以修改里面的东西(缓冲区溢出攻击)。尽可能使用c++风格的字符串string类型。
    
    动态数组创建,c语言,malloc(n*sizeof(int)),free(a)。c++ new int[n]和delete[] a;
    int *a = new int[10];没有初始化。int *a = new int[10]();初始化了
    string *astr = new string[10];使用默认的构造函数进行初始化;
    数组等的循环,一般用指针,专业点,可以认为指针是数组的迭代器。
    int *ai = new int[10];
    for(int *p= ai; p!=ai+10; ++p){
       *p=11;//通常通过指针作为迭代器,给数组ai循环初始化操作;
    }
    
    c与c++转换
    string 和char相互转换:string类型用c_str()转换后赋值的时候,对象必须是const,const char *= st.c_str();
    数组和vector转换:int a[6]={1,2,3,4,5,6}; vector<int> v(a, a+6); 复制的时候,后面的是不包括的,所以是a+6,而不是a+5,或者用迭代器vector<int>::const_iterator 
    vector<int> ivec;
    int ival; //tmp变量,很重要
    while(cin>>ival){ivec.push_back(ival) }//input data to vector; 创建动态数组 int *a = new int[ivec.size()];动态创建一个数组
    字符串数组的c实现为:
    vector<string> svec;
    string sval;
    while(cin>>sval) svec.push_back(sval);
    char **c = new char*[svec.size()]; //赋值时,注意最后一个是
    赋值可用中间变量char *tmp = new char[svec.size()];
    然后将c[i]=tmp; //因为c是二重指针,所以存放的是地址;释放的时候也得用for循环。
    
    多重数组
    int a[n1][n2]; int (*ip)[4];//注ip是一个指针
    常常用typedef简化指向数组的指针,例如:#typedef int int_array[4];然后,写int_array *ip;与以上的ip一样;这样可以避免丢失括号而导致ip不是指针的问题,ip=a;表示指向a的第一行,即ip是一个指针,所以使用ip取a中值时,还得使用一个指针;
    int *ip[4]; //ip是一个数组,区分以上的有括号的情况
    
    算术运算符
    double 10/3; 会等于3,除号是整除和小数除
    cout<<-21/-8;会等于-5,如果一正一负,结果可能是正也可能是负 -21/8 c++中是不确定的
    
    箭头操作符与指针
    Dog *p;
    p=new Dog();
    p->foo(); 和(*p).foo();等同,其中,foo为类Dog的方法
    指针的指针,一般用一个临时指针,将中间值赋值给它;
    vector<string*> spvec;
    string str;
    while(cin>>str)
    { string *pstr = new string;//相当于临时指针
      *pstr=str;
    spvec.push_back(pstr);
    }
    这里一定要释放
    vector<*string>::iter = spvec.begin();
    while(iter != spvec.end()){ delet e * iter;iter++;}  //一般不直接操作spvec,而是通过迭代器,操作。
    
    条件操作符,一般if 类型的可以用这个替换(a>b)?a:b; 不过慎用,避免嵌套,看起来繁杂不好理解
    
    new delete
    new的时候,如果是内置类型,一般要用括号;
    例如int *a = new int();调用默认构造函数初始化
    如果int *a = new int; 如果是内置类型,则没有初始化,很危险。
    如果是在类类型,在main中创建的,这是等同的;所有的new 一定要使用delete撤销
    
    强制类型转换符
    C++新式的static_cast dynamic_cast reinterpret_cast const_cast 和传统C风格的;
    举例:double dPi=3.1415926; int nNum=static_cast<int>(dPi);//这种啰嗦的写法提醒作者注意,这里用了强制转换,其实是和C风格一样
    避免使用强制类型转换,C++一般不提倡c风格的在转换,因为没有检查,而dynamic_cast等,如果转换成果,返回值不为空,如果为空,表示转换不成果,例如:int n = dynamic_cast<int>(val);可以使用if(n) 判断是否成功
    
    文件操作,抛出异常try catch,throw相结合的方式
    FILE *input=fopen("a.txt", "rb");//常常对fopen进行判断,是否打开成功
    FILE *output=fopen("b.txt", "rb");
    一定要记得关闭fclose(input);fclose(output);
    int size = fread(dst, sizeof(float), num, input);//size为读取的实质大小,dst为目标存储位置,sizeof(float)每次读多大的大小,num是总共读多少,input为输入文件流
    int size_out = fwrite(dst, sizeof(float), num, output);//这里
    用if(input==NULL) throw 1;//抛出异常,可以输出,数字,字符串,类对象。
    代替if(input==NULL) return 1;
    int func(){FILE *input =fopen("a.txt","rb");if (input==NULL) throw 1;}然后用以下部分处理异常;
    try{func();}catch(int e){printf("e:%d",e);} catch(const char *e){}
    
    标准异常类:exception,runtime_error rang_error,invalid_argument在stdexcept中),bad_alloc在头文件<new>中,
    例如:try{}catch(bad_alloc err){cout<<"allocate exception";}
    int function(int a){if(a<0)throw out_of_range("data not lower zero");}//定义自己的异常程序。调用的时候,用try catch即可。
    设计自己的异常类,可以在自己定义的类中,添加类成员,这个类成员一般可以继承已有的异常类,然后实现里面的what方法:virtual const char *what() const throw(){ return "your message";}
    602653
    使用预处理进行调试,
    第一使用#ifndef NDEBUG 方式,二,assert(头文件cassert)
    获取对应的信息,三,使用__FILE__ __LINE__ __DATE__ __TIME__ 直接和内部定义的宏一样返回对应的文件位置,行数,日期时间等,直接使用。assert(3==(1+2)),如果不相等,则返回详细错误信息。其中NDEBUG为内部定义的宏,不使用调试的意思,如果用了,assert也将不起作用
    
    引用形参;目的:一为了修改值,能传递回来,第二,防止赋值,降低操作时间,第三,使用const,避免修改
    function(string a); 如果传递进去的a过长a="aaaaaaaaaaaaaaaaaaaaaa";会导致效率低下,特别是对a还不做修改时,强烈建议使用const 引用。function(const string &a);
    指针引用 function(int *&val)val是个引用类型,同时也是指针。
    例如:定义交换指针函数 swap(int *&a, int *&b); int a=9; int b=8; int *pa=&a; int *pb=&b;
    swap(pa, pb);最后pa指向了b,pb指向了a。
    
    vector list deque作为形参的时候,一般不是直接传递进入的,而是使用迭代器作为形参
    例如:function(vector<int>::iterator begin, vector<int>::iterator end);
    
    返回值为引用或者指针的时候,一定要注意,不要反悔一个函数结束时,此变量就不存在的对象:例如:int * function(){ int a = 0return a;}//这是很危险的,因为函数结束的时候,a就不存在了。切记。常引用或指针,不能赋值给非常引用或指针;
    举例:改变字符串中的某个字符
    char & change_s(string &str, int i){return str[i];}
    调用时 string strv("aaa"); char &c=change_s(str,1); c="i"; //结果str变为了aia;因为这里传递进去的是引用,返回的也是引用,多以对原来的变量进行了修改,也是对原来的引用变量修改。而不是赋值操作,一定要区别,并且返回为引用指针的时候,一定要小心; 
    
    大量的递归调用会占用内存和时间。默认实参,一般在函数声明处写。
    
    内联函数一般放在头文件中,节省时间开销,递归和大函数,避免使用内联函数,内联函数在编译的时候,会展开。可以理解为避免了调用操作,而是直接展开替代。内联函数的编译对编译器来说,必须是可见的,所以一般得放在头文件中。
    
    class
    要变成对象了,才能使用,在类的定义中,没有对象,一般用this(类似于参数)表示,也可以不写,写上更好,表示这个变量时当前对象的。
    例如
    class Sale{
    private:
    bool val;
    publicbool function(const Sale sa){
        this->val = sa.val; //this表示这里Sale的对象,不是这里的sa
    }
    }
    只有静态成员才能直接使用初始化,一般的变量只能通过构造函数进行初始化,初始化的时候,一般用初始化列表形式进行初始化例如上面的用Sale():val(true),val1(0){};多个变量可以使用""号隔开。初始化过程中,一般基本的数据类型都必须初始化,一些有默认进行初始化的类型,不用进行初始化,例如string类型,就可以不用初始化,会使用默认的初始值进行初始化
    
    重载与作用域:
    重载函数一定要写到一个作用域。防止函数被屏蔽或隐藏现象。
    变量名和函数名同名,可能导致函数屏蔽:例如 int init = 0; int a = init();其中init()为函数,这样会导致函数init();函数不可见,会出错,这种现象叫函数隐藏或者屏蔽。function(int *const a);和function(int *a);不能构成重载,但是function(int *a); 和function(const int *a);构成重载;
    
    指向函数的指针(函数指针变量)(一般用typedef简化其声明)
    bool (*pf)(int a, int b);声明了一个指向函数的指针,表示指向函数类型为参数表为(int, int)返回值为bool类型的函数指针,这里的(*pf)不能去掉。调用的时候,就是
    pf=functionname;或者pf=&functionname 然后直接使用pf(3,4);或者(*pf)(3,4);.和调用functionname(3,4)一样。因为使用函数指针的时候,写起来太复杂。所以一般使用typedef 简化。
    例如:typedef bool (*dPf)(int a, int b); 在使用的时候,就直接使用dPf pf;声明函数指针变量,就像直接使用bool (*pf)(int a, int b);一样,并且可以方便的定义多个函数指针变量,dPf pf1, pf2;非常方便。函数指针因为是个变量,所以可以作为函数形参,例如一个函数调用另外一个函数的时候,可以将另外一个函数的指针传递进入,实现一个函数调用另外一个函数。函数指针的形参必须和指向的函数的参数类型精确匹配。
    
    流对象是不能复制的,所以要传递流对象的时候,一般用引用类型或者指针。
    int function(ofstream ofs); ofstream of; 使用的时候function(of)会失败,因为流对象不能复制。把函数改为int function(ofstream &ofs)后,则可以这么使用了。
    
    流的条件状态。if(cin.bad()) cin.fail() cin.eof() cin.good() cin.ignore(200, "
    "),要么忽略前两百个,要么忽略到
    . cin.setstate(XXX), cin.rdstate()等等
    如果输入int a; cin>>a,你输入的str,check这个流的状态的时候,可以知道cin.fail()为真,也就是这个输入是失败的。cin.clear()流状态清理到正常的 状态
    流对象的字符串为C风格的字符串,例如ofstream f; f.open(str.c_str())
     
    逗号运算符,是逗号后面的为条件。例如while(cin>>a, !cin.eof()),其实while(cin>>a)当eof fail bad的时候会结束输入。而while(cin>>a, !cin.eof())只有到流的末尾时,才结束。另外注意,文件流的状态不会因为close了,而跟新,所以连续的用某个流open文件的时候,一定要记得用clear来恢复流的状态,然后再使用。
    ifstream fs("file.txt"); 或者 ifstream fs;fs.open("file.txt");两种方式,将ifstream绑定文件。
    
    文件模式:
    in,out,app后面添加,ate定位到文件最后的文件定位指针,trunc截断,覆盖,binary
    
    字符串输入输出流 stringstream istringstream ostringstream 是内存操作;cout cin 显示在屏幕,不是内存操作。
  • 相关阅读:
    SuffixArray
    CodeForces722C
    CodeForces1000C
    浅谈定积分
    浅谈线段树
    飞行员配对方案问题
    FhqTreap的区间翻转
    NOI2004郁闷的出纳员
    二分图匹配
    Far Relative’s Problem (贪心 计算来的最多客人)
  • 原文地址:https://www.cnblogs.com/hansjorn/p/5215579.html
Copyright © 2020-2023  润新知