美文网首页
C++ primer plus V6 泛读知识点

C++ primer plus V6 泛读知识点

作者: _layty | 来源:发表于2018-08-17 22:14 被阅读0次

    2018年8月17日 22:14:16


    title: C++PrimerPlus读书笔记
    typora-root-url: ..
    typora-copy-images-to: ..\img\root
    date: 2018-08-15 22:55:29
    tags:
    c++
    学习
    categories:
    学习


    C++PrimerPlus读书笔记

    第一章

    • C++融合了C的面向过程,添加了以类为代表的面向对象,模板支持的泛型编程.
    • C是一种结构化编程的语言.强调算法.C++ 强调的是一种数据结构
    • 扩展名大小写,c是标准的c,C是支持C++的C

    第二章

    • end1\n相比,都可以执行换行,但是会刷新输出缓冲.
    • token是代码中不可分割的元素
    • 声明包含了定义声明和引用声明两种形式
    • cin中的<<是进行了运算符重载,所以他能实现各种格式输出
    • linux使用命令链接函数库g++main.c -lm
    • using namespace 放在函数中,则只对函数起作用,放在函数外,则对所有函数有用

    第三章

    • 内置类型分为基本类型(整数和浮点数)和复合类型(数组,字符串,指针,结构)
    • 以两个下划线或者一个下划线和大写字母打头的名称被保留,以及一个下划线打头的用作全局标识.P38
    • short至少16位,int至少与short一样长,long至少32位,至少=int,long long 至少64位,至少=long,在limits中限制
    • 变量初始化方式
      • c++ 可以使用类似int i(60);初始化变量,这类似将int看作一个class,60为构造函数的参数?
      • 也可使用{},如果括号为空则为0,可以 int enum{7},也可以 int a={2}.
    • 数字后面的后缀 u/U表述无符号,l/L标识long
    • cinput()可以输出char的字符
    • 通用字符名以\u或者\U打头,\u后面是8个十六进制位,\U后面是16个十六进制位,用来扩展编码,
    • wcha_t可以存储汉字和日文,长度由编译器确定,是一种整数类型,不能使用cin/cout,可以使用wcin,wcout.
    • char16_t(u作为前缀)和char32_t(U作为前缀)也是用来标识字符
    • C中一般将0解释为false
    • ==const==在C和C++中有所不同,一个是作用域规则,一个是const可以声明数组长度
    • 可以使用E来标识浮点数,标识10的多少次方,d.dddE+n是将小数点右移,~n是左移
    • 浮点类型有float,double,long double.float至少32位,double至少48位且不少于float,long double至少=double,可以从float.h看到限制,c++在cfloat
    • 使用cout.setf可以设置显示精度
    • 浮点常量默认使用double存储,可以用后缀f,F指定float,用L,l指定Longdouble
    • ==float只能保证6位有效精度==
    • 优先级,附录D.先判断优先级分组,再判断结结合性,所以同一优先级的结合性是一样的,从左往右的结合性说明对于操作数,先运行左侧的运算符.P60
      • 注意:20*5+30*6,是先计算左边的20*5还是右边的30*6主要靠编译器的实现.虽然*的结合性是从左到右,但是并不是作用在同一个操作数
    • 简单的运算符重载:
      • 9/5 int除法
      • 9.0/5.0 double
      • 9L/5L long触发
    • 潜在的类型转换p64
      • 赋值时的隐式转换
      • 表达式中有不同的类型
        • short提升到int..这个在c里面应该没有
        • 不同类型,小类型转换为大类型
      • 参数传递
    • 强制类型转换
      • 形如 (int)tepm
      • c++新增 int(temp),这样int看着就是一个函数风格
      • c++还有强制类型转换运算符号4种P65
        • static_cast <long> (temp)

    第四章

    • 初始化一个数组为0,只需要显示的初始化第一个元素为{0}
    • c++中有以下新的特性
      • int a[4]{1,2,3,4};
      • 在{}可以不写值,都为0
      • 列表初始化可以禁止一些缩窄的转换 比如float到int
    • 数组的替代复杂用法:模版类vector和模版类array
    • cin默认读取到空白,可以使用getline和get读行,使用getline会丢弃下一个换行,get并不会,
      • cin.clear
    • string类的简单用法
      • 允许直接相互赋值
      • 允许使用+
    • 支持其他编码格式的字符串
    • 支持RAW的字符串,里面就没有转义了,以R开头,形如R"(xxxxxxxxxxxxxx)",允许在R"(加上xxx,这样之后,尾巴也要使用)"加入一样的,形如R"xxx(YYYY)xxx",中间的YYY是实际的
    • 可以将RAW与w_char等结合,如Ru,UR暂时放着
    • 在定义变量的时候可以省略struct,与c的结构相比,允许放置成员函数,同样支持位域
    //声明结构类型
    struct ab{
    int a;int b;
    }
    //c这样声明变量
    struct ab tmp1;
    //c++  可以省略struct
    ab tmp2;
    
    //还有以下用法
    
    struct structName
    {
        int a ; int b;
    }tmpname;
    当有tmpname的时候可以省略structName,这样只能用一次,这时候还可以直接初始化.
    struct 
    {
        int a ; int b;
    }tmpname={0,1}
    
    //还可以这么赋值,c99以后支持的,韦东山有讲
    tmpname={.b=xxx;.a=xxx}
    
    • 公用体支持匿名公用体,这样可以少写这个公用体的名字
    
    #include <stdio.h>
     
    struct person
    {
        char    *name;
        union
        {
            char gender;
            int  id;
        };
        int      age;
    };
     
    int main(void)
    {
        struct person jim = {"jim", 'F', 28};
     
        printf("jim.gender = %c, jim.id = %d\n", jim.gender, jim.id);
     
        return 0;
    }
    
    • 如果只是为了使用枚举常量,不声明枚举变量,可以忽略枚举名称,也就是匿名枚举.c++中的枚举默认是int,但有>int的,则使用4字节long,这有个词==作用域内枚举==
    • int * a, b; b是int.不是指针
    • 使用new为指针分配变量 int * pt = new int;//pt是个指针,new是从堆heap和自由存储区中分配内存,定义变量是在栈.(单片机的有点不一样)
    • delete释放内存 int* pt=new int;delete pt;不能使用delete释放释放过的内存,结果未知,也不能释放定义变量的内存.delete 对应的是地址,感觉应该是那个地址包含了长度,类型的链表, 可以delete 同样地址的指针,int* pt2;pt2=pt;delete pt2;
    • 数组名和指针的区别:1 数组名是常亮,不能执行运算 2. sizeof指针=4 32位系统
    • ==数组名取地址==,对于一个数组 short tell[10];,存在以下三个地址
      • &tell[0]=数组的地址
      • tell=&tell[0]=数组的地址
      • &tell,这个是一个二级指针了,他指向了tell,也就是*(&tell)=tell,指向了包含20个元素的数组
        • []优先级高于*,所以我们定义一个指针指向了一个20元素的数组这么定义 short ( *p)[20]=&tell
    short tell[10];
    cout<<tell<<endl;
    cout<<&tell<<endl;
    //从地址上看两者是相等的,但是&tell[0]=tell是一个2字节的内存地址,&tell是一个20字节的地址,所以tell+1是地址加2,&tell+1是加了20,
    //可以这么来一个指针 
    short (*p) [20]=&tell;
    
    • 结构体指针成员的获取,a->b 或者 (*a).b
    • vector 模版类,使用vector <int> vi; vector <char> ch(10);
    • 模版数组array,与模版类不同,他是用栈的 ,但是也支持new和delete array<int,5> ai;与模版类不同,他创建的对象大小是固定值,不能是变量
    • 数组,模版类,模版array都可以使用数组下标访问,诸如越界a[-2]默认情况也是允许的跨界了,如果要检查可以使用模版类/模版数组的成员函数at,形如a.at(1)=a[1]模版类是动态数组的替代,模版类array是静态数组的替代.模版数组支持直接复制.

    第五章

    • 在c中,表达式成立为1,false为0,但在C++引入bool后,关系表达式是来判断bool的,C++在需要整数的时候将true和false转换为1,0,在需要bool值的时候0为false,非0为true
    • 设置显示格式:cout.setf(ios_base::boolalpha);设置为显示bool还是true
    • 表达式是没有分号的,有些表达式会对内存变量等有影响,有些没有,加上;就是语句了,所以可能会有a+3;这种没有意思的语句.
    • 对于在for内部的int变量,新的标准是在==内部有效==,老的标准是将定义置于for之前for(int a; a<5;a++)
    • using声明与using编译指令 Using std::coutUsing std
    • 顺序点与执行顺序的问题,在循环语句中,一个表达式结束才会进入另外一个语句,表达式结束意味其中的++等操作已经实现了其副作用,但是类似 y=(1+a++)+(6+a++),没有规定左右哪个先执行
    • 对于类而言,前缀++效率更高
    • 优先级浅析*++p 前缀递增与*优先级相同,从右往左,所以先结合右 ++pt,再*(++pt)
    • x=*pt++,后缀优先级更高,所以先 pt++,但是后缀运算意味着对原来的地址操作也就是x=*pt
    • 逗号运算符表达式,返回右侧的值
    • for允许使用类似for int i : iarrar[10]或者for int &i : iarrar[10]来修改数组
    • C++改变参数的值可以不使用指针,只需要将参数声明为引用istream& cin.get(char& var);,这么用cin.get(a)就能改变A的值,关于引用能改变参数值,其实就是传递地址了

    第六章

    • 文件操作

    • cin输入P187

      https://blog.csdn.net/K346K346/article/details/48213811

      cin输入流的机制是:

      当遇到无效字符或遇到文件结束符(不是换行符,是文件中的数据已读完)时,输入流cin就处于出错状态,即无法正常提取数据。此时对cin流的所有提取操作将终止。在 IBM PC及其兼容机中,以Ctrl + Z表示文件结束符。在UNIX和Macintosh系统中,以 Ctrl + D表示文件结束符。当输入流cin处于出错状态时,如果测试cin的值,可以发现它的值为false(假),即cin为0值。如果输入流在正常状态,cin的值为true(真),即cin为 一个非0值。可以通过测试cin的值,判断流对象是否处于正常状态和提取操作是否成功。如:
      if(!cn) //if表达式判断为真时cin输入流处于出错状态,无法正常提取数据
      cout<<"error";

      错误处理

      • 重置cin以接受新的输入
      • 删除错误的输入cin.clear()是用来更改cin的状态标示符的。通俗的讲就是将一个出错的“流”恢复为“好”,并设置goodbit状态位。
      • 提示输入
      #include<iostream>
      const int Asize = 5;
      int main()
      {
          using namespace std;
          int golf[Asize];
          int i,sum = 0;
          float ave;
          for(i = 0;i < Asize;i++)
          {
              cout << "round # " << i + 1;
              while(!(cin >> golf[i]))
              {
                  cin.clear();
                  while(cin.get() != '\n')
                  {
                      continue;
                  }
                  cout << "Please enter a number:";
              }
          }
          for(i = 0;i < Asize;i++)
          {
              sum = sum + golf[i];
          }
          ave = (float)sum / Asize;
          cout << ave << endl;
          return 0;
      }
      
      
      1. cin>> ,当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。但是如果读取成功,字符后面的分隔符是残留在缓冲区的,cin>>不做处理。
      2. cin.get 关于cin.get()和cin.get(ch)区别P159
      int cin.get();
      istream& cin.get(char& var);
      istream& get ( char* s, streamsize n );
      istream& get ( char* s,  streamsize  n, char delim )。
      
      • cin.get读取一个字符 cin.get或者cin.get(var),cin.get()从输入缓冲区读取单个字符时不忽略分隔符.cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。
      • cin.get读取一行,读取一行可以使用istream& get ( char* s, streamsize n )或者istream& get ( char* s, size_t n, streamsize delim )。二者的区别是前者默认以换行符结束,后者可指定结束符。n表示目标空间的大小。
        • cin.get(array,20);读取一行时,遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。这也是cin.get()读取一行与使用getline读取一行的区别所在.cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数可以将字符串读入C++风格的字符串中,即string类型。鉴于getline较cin.get()的这两种优点,建议使用getline进行行的读取。
      • cin.getline,cin.getline不会将结束符或者换行符残留在输入缓冲区中。
      istream& getline(char* s, streamsize count); //默认以换行符结束
      istream& getline(char* s, streamsize count, char delim);
      
      • exit()是定义在cstdlib中的,exit(EXIT_FAILURE),中间的EXIT_FAILURE是系统通信参数

      • ==文件操作==ifsream 和 ofstream,fstream

        • 判断是否成功打开 file.is_open

        • file.good能够判断错误,输入正确,并且没有EOF

        • 读取的时候不能超过EOP,如果遇到EOF,方法eof返true

          while(inflie.good())
          {
            infole>>value;
          }
          //还可以精简如下p197
          while(infole>>value)
          {
            //do
          }
          
          

    第七章

    • 二维数组作为参数传递示例
    int data[3][4]={{1,2,3,4},{2,2,3,4},{3,2,3,4}};
    int total=sum{data,3}
    
    //原型
    int sum(int (*pt)[4],int size)//这里(*pt)要有括号,否则就是 pt[4] 然后是个int 指针,是个指针数组了
    //或者
    int sum(int pt[][4],int size)
    
    • 局部指针不能返回,c++中使用new分配内存是允许的,可以在外部删除
    • 结构体名字知识结构的名称,需要&取址,早期的c不允许直接按值传递结构只能传递地址,c++允许传值,可以用指针,也可以使用引用
    • 结构体允许直接复制,里面的指针是浅复制
    • 模版类,数组模版传递指针作为参数void fill (std::array<double,3> *pa)
    • 递归,在递归中,每一层的局部变量都有字节的地址存储单元.
    • 函数指针,标识这是一个指针,指向了一个函数double (*pt)(int),pt是个指针,指向一个函数,一般情况下声明一个函数指针,可以先写出这个函数的原型,再将名字换成(pt),在这里(*pt)等同与函数名,可以直接使用(pt)(参数);
    • 指针函数,标识这是一个返回值是指针的函数double * pt(int),因为括号优先级高,所以先和pt结合,说明这是函数,返回值为double *
    • 在函数中,允许省略标识符,下面三个是一样的
    f1(const double ar[],int n)
    f2(const double [],int )
    f3(const double *,int )  
    
    • 函数指针数组const double * (*pa[3])(const*,int)={f1,f2,f3};
        1. pa是个数组,他的类型是*,也就是一个指向指针的数组
        2. 指针的类型是 const double * xxx(const double*,int),也就是说指针是个函数 xxx(const double *,int),参数是(const double* ,int),返回值是 const double *
    • auto 只能用于单值初始化,不能用于初始化列表,这个不太理解 P245,应该是 auto b=a; a是已知的一个值.
    ///都忽略参数
    
    //step1
    //pt是个指针,指向一个函数,
    double (*pt)(int)
    //pt是个函数,返回一个 double*
    double * pt(int) 
        
    //step2
    // pt是个函数,返回值为 double *
    const double * pt(const double *,int)
    //pt是个指针,指向一个返回值为 double*的函数
    const double * (*pt)(const double* ,int)
        
    //step3
    //[]优先级高于*,所以pt是个数组,类型为*,也就是是个指针的数组,数组里存的是指针,指向了一个函数
    const double * (*pt[3]) (const double* ,int)
        
    //step4
    //构造一个指针,指向step3,简单的理解就是将pt改为(*pt1)就ok,pt1指向step3的数组
    //1.pt是个指针  (*pt)
    //2.指向一个数组 (*pt)[3]
    //3.该数组的类型是个指针,我们定义一个数组,数组的元素类型为 int* 的话,这么定义  int* a[3];
        //同上,    (type)* (*pt)[3] 也就是↓
    const double * (*(*pt)[3]) (double * ,int)
    
    • const从右往左读.... 列入const int *p 就是p is a pointer to a int which is constant...其它的都可以那么读...

    第八章

    • 宏在某些情况下会有问题,不能传递参数,比如参数是(i++)这样的话使用替换可能导致内部有多次i++
    • 在创建引用变量中int & b=a;注意这里的&不是取址,而是类型标识的一部分,应认为是指向int变量的引用
    • 引用与指针的一个区别,必须在声明引用的时候初始化.更像 const指针
    • 早期的编译器允许引用是个常量,或者类型不匹配,为其创造一个临时引用,创建临时变量不会改变原值(类型不匹配的话)P263
      • 实参类型正确,但不是左值,比如常量
      • 实参类型不正确,但可以转换,比如一个long的范围比较小,转换为int,这种情况下一般需要加个const标注以下,因为不会改变引用值
    • ==引用中的匿名变量==...就是上面的临时变量
    • 可使用右值引用,使用&&
    • 如果不希望更改引用的值,使用const声明原型
    • 当函数返回值为引用,然后 a=fun(...),这样避免fun返回值先创造一个局部变量,可以直接复制.函数返回引用实际就是返回引用变量的别名 .注意:返回的引用不应该是个局部变量,就像指针一样
    • 基类的引用可以指向派生类的对象,这也就是说函数原型参数为基类,但你可以用派生类的对象
    • cout.setf() 格式化输出,返回的是所有配置,所以可以用返回值保存当前的配置P273
    • 关于使用指针或者引用:类使用引用,结构使用引用和指针,其他使用指针
    • 默认参数的右边必须是默认参数,调用是不允许跳过,比如fn(int a ,int b=1,int c=2),不能使用fn(1,,3),默认参数一般放在原型而不是实际定义中
    • 函数重载中有些参数是不能共存的,比如 x 与 &x
    • 函数模版,也就是参数的类型可以是尚未可知的,比如有一个 fn(int a) 和 fn(double a),如果内部执行步骤一致,以前我们需要写两个函数,现在可以把这个提取出来.
    //下面都可以,class是老的
    template <typename Anytype>//一般写作 template <typename T>
    template <class Anytype>
    void Swap(Antype &a, Anytype &b)
    {
        Anytype temp;
        temp=b;
        b=a;
        a=temp;
    }
    
    • 函数模板支持重载,与一般的重载函数一样,特征标需要不一样
    • 模板的局限性:
      • 一些操作无法执行,比如如果变量是个结构,那么运算符>;如果是数组,那=就不成立,等等..
      • 解决办法:1运算符重载 2 具体化模板定义
    • 对于一个函数名,依次是非模板函数>显示具体化模板>模板函数 包含他们的重载函数
    • 具体显示化格式:原型和定义以template<>打头,通过名称指出类型,显示化声明后必须要有具体的定义
    //模板
    template<typename T>
    void Swap(T &a, T &b);
    
    struct job
    {
        int a;
        int b;
    }
    
    //显示化声明,这里的Swap(Job)中的job是可选的,参数里面已经有了
    //可以简写 template<> void Swap(job &j1, Job & j2);
    template<> void Swap(Job)(job &j1, Job & j2);
    
    //显示化定义
    template<> void Swap(Job)(job &j1, Job & j2)
    {
        .....
    }
    
    
    • 还可以在函数使用的时候创建显示实例化cout<<Add(double)(x,m)<<endlP288

    • 具体到调用函数才会产生模板的实例,称为一个实例.C++支持

      • 隐式化实例
      • 显示化实例,这种实例需要这么声明template<> void Swap(Job)(job &j1, Job & j2),或者template<> void Swap(job &j1, Job & j2);,还支持函数中直接实例化例如cout<<Add(double)(x,m)<<endl
      • 显示具体化是指针对特殊的一些结构,做出不同的实例化的函数
    • 显示实例化话是模板的一个具体实例,因为模板生成函数一般是隐式实例化的,根据实参的类型生成函数。而显示实例化直接指定生成模板的哪一种实例。显示具体化是指模板的特殊行为,理论上模板接受不同类型的参数都会按照模板定义的那样去执行,显示具体化允许在特定的形参下重新定义函数的行为。

    • 模板函数的选择有一套复杂的规则,当完全匹配后,选择那个T最简单的方式

    • 模板是支持多个参数不定的template <class T1, class T2>

    • decltype 解决一些类型未知不定的情况P295,配合auto可以声明返回值的类型,注意decltype 中如果表达式式个左值,有两个括号的是引用,一个的是值的类型

    • 所谓的特征标,就是函数的参数列表,翻译想出的高大上的傻逼词语

    第九章

    • 多文件编译,头文件包含
    • 作用域表示这个东西在文件内多大范围可见,链接性表示外部文件的共享
    • 静态变量都会被先初始化,然后在初始化为其他值 bss
    • cv限定符...翻译出来的新玩意..就是const和volatile
    • mutable,表示即使结构或者类变量为const,但是限定为mutable的某个变量也可以被修改
    • const 在c++中,会将全局变量限定为static,这么做的原因是可以将const int a =2这种形式放到.h中,反复包含.当然也可以强制更改这个属性,在const前加上extern .c中没有这个说法.

    todo

    ==数组名取地址==

    for里面的作用域

    备忘:

    • (),[]优先级高于指针
    • ++高于*,&指针优先级

    相关文章

      网友评论

          本文标题:C++ primer plus V6 泛读知识点

          本文链接:https://www.haomeiwen.com/subject/anfxiftx.html