c++笔记(一)

这里写的主要是一些c/c++值得注意的地方和c++primer笔记,方便以后回顾,复习c++,当然会有一些错误,发现后再改正 //当形参引用时,数组不能转化为指针//“\”是连接符,当宏定义用多行时常用1:c中不可以连续赋值;   c++可以,如int a,b,c;a=b=c=1;2:一般int main(){        ...       }        如果main...
摘要由CSDN通过智能技术生成

这里写的主要是一些c/c++值得注意的地方和c++primer笔记,方便以后回顾,复习c++,当然会有一些错误,发现后再改正

 

//当形参引用时,数组不能转化为指针
//“\”是连接符,当宏定义用多行时常用
1:c中不可以连续赋值;
   c++可以,如int a,b,c;a=b=c=1;


2:一般int main(){


        ...
       }
        如果main函数里不加system("pause");的话,程序运行后立马闪退,为了让程序暂停,也可以加
     cin.get();(c++中,)c中可以加getchar();(输入后需按回车键才能发送到输出流),getche();(不      用按回车键,但输入的字符不会回显到屏幕上 ),getch();(不用按回车键,回显)
      为什么呢?就已这个例子来说吧
     int main(){
cout << "How many carrots do you have?" << endl;
int n=0;
cin >> n;
cout << "Here are two more;"<<endl ;
cout << "Now you have " << n + 2 << "carrots" << endl;
cin.get();
        cin.get();
//system("pause");
return 0;
    }        
      当我们根据提示输入一个数字,比如12,然后按回车,其实输入缓冲区里可能还有数据,按回车       后,第一个用来接收缓冲区里的数据,第二个用来停顿(当然用system("pause");最好) 


3: c++在c的基础上又增加了long long型,sizeof(long long)=64;(一般来说);
     bool型,值为false或true


4:  可以通过包含头文件climits来查看整型的最大值最小值(climits专门用于检测整型数据数据类型        的表达值范围。)
        int main(){
int n_int = INT_MAX;      //int型的最大值,下面依次类推 
short n_short= SHRT_MAX;  //这里写法注意,是SHRT_MAX;
long n_long = LONG_MAX;
long long n_llong = LLONG_MAX;
cout << "int is " << sizeof(int) << " bites" << endl;
cout << "short is " << sizeof(short) << " bites" << endl;
cout << "long is " << sizeof(long) << " bites" << endl;
cout << "long long is " << sizeof(long long) << " bites" << endl << endl;
cout << "Maximum values:" << endl;
cout << "shor:" << n_short << endl;
cout << "int:" << n_int << endl;
cout << "long" << n_long << endl;
cout << "long long:" << n_llong << endl;
cout << "The minumum int value:" << INT_MIN << endl;
cout << "Bits per byte:" <<CHAR_BIT << endl;   //CHAR_BIT:char的二进制位数(bit)
system("pause");



return 0;
}


5: c++可以这样初始化:int a(10);//a=10;
                       int b{10};//b=10;
                       int c={};//c=0
                       int d{};  //;也可以不使用=
     为什么要用大括号呢?因为大括号初始化可以初始化任何类型的变量(可以加等号,也可以不加)


6: 如果知道变量的值大于16位整数的最大可能值时,则用long,即使系统上int为32位(即sizeof    (int=4)),也应该这么做,这样,
    将程序移植到16位系统时,就不会突然无法正常工作。如果存储的值超过20亿,可使用long long.


7: 可以这样输出八进制,十进制,十六进制
   cout<<oct<<45;   //octal 八进制的
   ocut<<dec<<45;   //decimal 十进制的
   cout<<hex<<45;   //hexadecimal  十六进制的  


8:  转义字符\a表示振铃字符(ASCII码为7),可以使终端扬声器振铃


9:float a = 2.34e+22f;
float b = a + 1.0f;
cout << "a=" << a << endl;
cout << "b-a=" << b - a << endl;
   b-a应该为1,可是运行程序时输出的确是
    a=2.34e+022;
    b-a=0;
    问题在于,2.34+22是一个小数点左边有23位的小数,加上1就是在第23位加1,但float类型只能表示    数字中的前6位或前7位,因此修改第23位对这个值不会有任何影响。




11: c中的宽字符基于wchar_t数据类它在几个头文件(包括wchar.h)中都有定义,像这样:
     typedef unsigned short wchar_t;
      因此,wchar_t数据类型与无符号短整型相同,都是16位宽
     定义一个宽字节可以这样:
     wchar_t c=‘A’;直接输出的话cout<<c<<endl;结果相是应的ASCII值,这里就是65了
     还可以定义指向字符串的指针  wchar_t *p=L"hello";//注意要在前面加L(表示long);
                                                    //cout<<sizeof(p);结果是4
                                                   // sizeof(*p)是2(即h的字节数(宽))
     也可以直接定义宽字符串wchar_t c[]=L"hello";   // sizeof(c)是12(5个字符,1个字符串结束标志,每                                                     个占2位)
     但这样直接输出cout<<c<<endl;结果是c的地址
     cout<<p<<" "<<*p<<endl;输出的是p的地址和104(h的ASCII码);
     宽字符想要输出对应的字符,应用wcout。
     wchar_t是用两个字节存储的,例如字符串(wchar_t )“hello!”,intel将其在     内存中存储为
           48 00 65 00 6c 00 6f 00 21 00
     wchar_t *p=L"hello";
     printf("%d\n",strlen(p));
     所以如果这样的话 ,结果是1;因为strlen函数获取字符串的第一个字符后就遇到了0,即结束标志
      ,而单字节就不会有这种情况,为了解决这个问题,有宽字节的strlen版本,就是wcslen(wide 
      character string length)
12:c++中,求字符串长度不是c中的strlen();而是string.size();或string.length;
     string a="hello";
     cout<<a.size()<<" "<<a.length()<<endl;


13 :##表示粘贴符号
   比如# define T(x) L##x
       如果定义T("hello"),就相当于L"hello";


14:c++中的强制类型转换
    typename(values)//更像是函数调用
    c中: (typename)value
    c++还引用了4个强制类型转换运算符,对它们的使用要求更为严格,例如:
    static_cast<typename> (value)
     


    ===================================================================================


       c++中,如果两个类型有关联,比如int型变量和float型变量可以相互转换,举个例子:
  int i=3.14+1;//编译器会警告可能会丢失数据,但不会报错
相加的两个类型不同,c++不会直接将两个不同类型的值相加,而是先根据类型转换规则将类型统一后再求值,这些是自动进行的,不用程序员操心,有时甚至不用程序员了解,被称作"隐式转换";
 其他类型的隐式转换:
  1):数组转换为指针:
          int arr[5];
          int *p=arr;//arr转换为指向数组首元素的指针
        当数组被用作decltype关键字的参数,或者作为取地址符(&)、sizeof         
     以及typeid等运算符的运算对象时,上述转换不会发生,同样的,如果   
     用一个引用来初始化数组,上述转换也不会发生,当在表达式中使用函       
     数类型时会发生类似的指针转换


   2)指针的转换
       c++还规定了几种其他的指针转换方式,包括常量整数0或者字面  
     值,nulllptr能转换成任意指针类型;指向任意非常量的指针能转换成  
     void *;指向任意对象的指针能转换成const void *;


   3)转换成布尔类型;
        存在一种从算术类型或指针类型向布尔类型自动转换的机制
   4)转换成常量:
        允许将指向非常量类型的指针转换成指向相应的常量类型的指针,
      对于引用也是这样,比如:
      int i;
      const int &j=i;  //可以将非常量转换成常量的引用
      const int *p=&i; //可以将非常量的地址转换成const的地址
      int &q=j,*r=p; //反之则错误


   5)类类型定义的转换:
       类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一
     种类类型的转换;
        string s,t="a string";//字符串字面值转换为string 类型
        while(cin>>s)        //cin转换为布尔值 


显示转换
    1)命名的强制类型转换
          cast-name<type>(expression);
        type是转换的目标类型而expression是要转换的值,如果type是引用
      类型,则结果是左值,cast-name是static_cast,dynamic_cast,
      const_cast和reinterpret_cast(reinterpret)中的一种,


          a.dynamic_cast:
          dynamic_cast支持运行时类型识别,cast-name指定了执行的是哪
       种转换


          b.static_cast:
            当需要把一个较大的算术类型赋给较小的类型时,static_cast
           非常有用,此时不会警告丢失数据了;
             static_cast对于编译器无法自动执行的类型转换也非常有用,
           例如,可以使用static_cast找回存在于void *指针中的值
              void *p=*d;//任何非常量对象的地址都能存入void *
              double *dp=static_cast<double *>(p);
            //将void *换回初始的指针的类型
              当把指针存放在void *中,并且使用static_cast将其强制转
            换回原来的类型时,应该保证指针的值保持不变,因此,必须确
            保转换后所得类型就是指针所指的类型,类型一旦不符,将产生
            未定义的后果


           c.const_cast:
              const_cast只能改变运算对象的底层const,
               const  char *pc;//pc是指针,指向const char类型,这里
             //的const是底层const,比如char *const pc,这个const就是
             //顶层const,个人觉得没必要刻意去记,这些东西很好理解
               char *p=const_cast<char *>(pc);//正确,但是不能改变p所
             //指对象的值




             d.reinterpret_cast
                 reinterpret_cast通常为运算符对象的位模式提供较低层
               次上的重新解释,比如:
                 int *ip;
                 char *pc=reinterpret_cast<char *>(ip);
                 请牢记pc所指的真实对象是一个int而非char,如果把pc当
               成普通的字符指使用就可能在运行时发生错误,例如:
                  string str(pc);//这可能导致异常的运行时行为
                   使用reinterpret_cast是非常危险的,上面这个例子很
               好的证明了这一点,其中的关键问题是类型改变了,但编译                 
               器没有给出任何警告或错误的提示信息,当用一个int的地址
               初始化pc时,由于显示地声称这种转换合法,所以编译器不
               会发出任何警告或错误信息,接下来再使用pc时就会认定它
               的值是char *类型,编译器没法知道它实际是指向int,这种
               错误很难发现 


          2)旧式的强制类型转换
                早期的c++中,显示地进行强制类型转换有两种形式:
                type (expr); //函数形式
                (type) expr; //c语言形式
      
    ===================================================================================


15:  c++11新增了一个工具,让编译器能够根据初始值的类型推断变量的类型,为此,它重新定义了auto,auto是c语言的一个关键字,但很少使用
      auto x=2.1;//x是double型


16:cin可以读取一个字符串到输入流,但是如果用cin输入时,输入的字符串含有空格键,tab   键,回车键等,就会结束输入,这是面向单词的输入,
   istream中的类(如cin)提供了一些面向行的类成员函数:(比如定义了一个数组name[size])getline(name,size)和get(name,size),区别是getline()输入结束后就会丢弃换行符,而get()不会(即缓冲区还有换行符)


17:char a[] ="string";
char *p = a;
cout << "a=" << a << " &a= " << &a << endl;
cout << "p=" << p << " &p=" << &p << " (int *)p=" << (int *)p << endl;
    结果a=string &a=0018F7c0
        p=string &p=0018F7B4 (int *)p=0018F7c0


18:  通常,cout在显示bool值之前将其转化为int,但cout.setf(ios:boolalpha)(老式c++)和cout.setf(
        ios_base::boolalpha)(c++11)函数调用设置了一个标记,命令cout显示true和false,而不是1和0
        int a;
cout << (a>3) << endl;
cout.setf(ios_base::boolalpha);
cout << (a>3)<<endl;


19:对于i++和++i,如for(int i=0;i<n;i++)和
                     for(int i=0;i<n;++i)
    在c++内置类型中,没有差别,但如是用户自定义类型中,++i效率更高,直接将i+1然后进入下一循环,而
   i++是先复制一个副本,将其加1,然后再将副本返回


20:  一个细节,值得注意
        int i = 8;

       if (i++==9||i==9)

       cout << "yes" << endl;

       else cout << "no" << endl;
      c++规定,||是个顺序点,也就是说,先修改左侧的值,再对右侧进行判定(c++11的说法是,运算符左边       
     的子表达式先于右边的子表达式)冒号和逗号运算符也是顺序点
      左边i++==9  这里i还是8,然后到右边,i就是9了,所以if里面为true


21:c++从c继承了一个与字符相关的,非常方便的函数软件包,它可以简化诸如确定字符是否为大写字母,数字    
    标点符号等工作,这些都在cctype(c中是ctype.h)中定义的,ep:ch是一个字母,则isalpha(ch)函数返回      
     一个非零值,否则返回0;同样,如果ch是标点符号(如逗号或句号),函数ispunct(ch)函数返回true、(   
     这些函数的返回类型为int,而不是bool,但通常bool转换竜让您能够将它们视为bool类型)
    使用这些函数就方便多了,例如:
     if(ch>='a'&&ch<='z'||ch>'A'&&ch<'Z')
     可以用if(isalpha(ch))代替
     还有很多函数,请看C.Primer.Plus (197页)
     
22:for循环可以这样用
    int a[5] = {1,3,5,7,9};
for (int i : a)
     cout << i << endl;
   结果输出数组a里的全部元素


23:通常,在输入字符,判断何时结束时一般都是按#键结束(或者
其他的一些按键) ,这样虽然大多数情况下不会有问题,但是
如果判断结束的字符是我们要输入的呢?这不就输入不了吗?如果输
入是来自文件·,则可以使用检测文件尾(EOF)来判断是否结
束输入,不过c++还可以用键盘模拟文件尾,过程是这样的,检测到
EOF后,cin将两位(eofbit和failbit)都设置为1。可以通过成员函
数eof()看eofbit是否被设置,如果检测到EOF,cin.eof()返回ture;
同样,用cin.fail()的话,返回true;一般使用较多的是fail(),因为f
ail()可以用于更多的实现


# include <iostream>
using namespace std;
int main()
{   char ch;
    int count=0;
    cin.get(ch);   //cin不会识别空格,tab,换行等空白键
    while(cin.fail()==false)//当没有检测到EOF,循环
    { 
        count++;
        cout<<ch;
        cin.get(ch);
    }
    cout<<endl<<count<<"characters\n";
    //结束输入时,按下ctrl+z,然后按回车
    system("pause");
    return 0;
}


24:int *p=new int[size];
    delete []p;


25:double(*p)(double a, double b);
p = max;//函数名就是函数地址
double a = p(4, 5);//函数名是函数地址,指针p指向函数的地址,所以p应该和max有相同的
double b = (*p)(4, 5);//p是函数指针,*p就是函数
cout << "a=" << a << endl << "b=" << b << endl;
    结果a和b一样,这两种用法都可以
    如果声明了一个函数,又定义一个指向该函数的指针,可以使用c++11的·自动类型推断功能,这样
   就方便得多,上面的就可以写成
     auto p=max;而不用写成
        double(*p)(double a, double b);
p = max;
      了,但是auto只能用于单值初始化,而不能初始化列表--
   还可以用typedef简化
     typedef  double(*type)(double a, double b);
      type p;     


26: 内联函数(inline)
     内联函数相比普通函数,调用时相当于直接使用函数的副本,而不用去找到函数的地址执行函数,所以
   速度相对稍快点,不过计算机运行速度非常快,所以也快不了多少,而且内联函数更占用内存
   声明和定义时必须都加上inline关键字,而且内联函数不能递归,关于内联,了解即可,一般用的比较少
   c中使用宏-----内联代码的原始实现
   # define SQUARE(X) X*X
   这是通过字符串替换实现的,而不是传递参数
   SQRARE(5.0);  //可以实现
   SQUARE(1+2);  //得到的不是9,而是1+2*1+2
   SQUARE(a++);  //得到的是a++*a++;a会自增两次
   这里不是为了说如何使用宏,而是为了说明当用c的宏实现某些功能时,应转化为内联


27: ofstream继承了ostream,ostream中的一些方法:
   1)setf()
         让你能够设置各种格式化状态,例如,方法调用setf(ios_base::fixed);将对象置于使用定点表               示法的模式,setf(ios_base::showpoint);将置于显示小数点的模式,即使小数部分为0 
   2)precision()
          指定显示多少位小数(假定对象处于定点模式下)。
    所有这些设置都将一直保持不变,知道再次调用相应的方法重新设置它们。
   3)width()设置下一次输出操作使用的字段宽度,这种设置只在显示下一个值时有效,然后将恢复到默认设置,默认的字段宽度为0
     函数file_it使用了两个调用 
     ios_base::fmtflags initial;
     initial=ios.setf(ios_base::fixed);//save initial formatting state
     ...
     iso.setf(initial); //restore initial formatting state
      方法setf()返回调用它之前有效的所有格式化设置,ios_base::fmtflags是存储这种信息所需的数据类型
     名称,因此,将返回值赋给initial将存储调用file_it()之前的格式化设置,然后便可以使用变量initial
     作为参数来调用setf(),将所有的格式化设置恢复到原来的值。


28:默认参数(声明时给默认值,定义时不要加,有些编译器会报错)
     例如函数声明void fun(int n=1);
     如果调用函数时忘了加参数,则默认传入的参数是1
      对于带参数列表的函数,必须从右向左添加默认值,例如
      int fun(int n,int m=2,int j=3);   //可以
      int fun(int n,int m=2,int j);     //不可以
       实参按从左到右的顺序依次赋给相应的实参,而不能跳过任何参数
       int n=fun(1,,4);//不可以


29:函数重载
     当调用函数时,如果未找到参数列表匹配的函数,c++会尝试使用标准类型转换强制进行匹配,如果     可以唯一匹配则匹配,否则若有多个可以
     匹配,将视为错误
     匹配函数时,并不区分const和非const变量
     但是将非const赋给const是合法的,反之则不行
     函数重载,不可以返回值类型不同,参数相同,但可以返回值类型,参数都不同
     函数重载不要滥用,仅当函数基本执行相同的任务,但是用不同形式的数据时,才采用函数重载,


30: cv-限定符:
    1)const
    2)volatile   (不稳定的;挥发性的;爆炸的)


                                31: 名称空间
    1)术语:
            a: 声明区域(declaration region)
            b: 潜在作用域(potential scope)
    2)名称空间
       用namespace创建名称空间
       ex: 
         namespace Jack{
             double pail;
             void fetch();
             int pal;
             struct Well{...};
         }
         namespaace Jill{
             double bucket(double n){...};         
             double fetch;
             int pal;
             struct Hill{...};
         }     
         名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中;名称空间是开放的,
        可以把名称加入到已有名称空间中,例如:
         namespace Jack{
             char *goose(const char *);
        }
         同样,若名称空间中为某函数提供了原型,可以再次使用该名称空间来提供该函数的代码
         namespace Jack{
            char *goose(const char *)
            {...}
          }
         如果使用using namespace Jack;
          局部变量会隐藏Jack里同名的变量,


31:初始化string对象的方式
     string s1;  s1为空串
     string s2("abc"); 用字符串字面值初始化s2
     string s3(s2); 将s3初始化为s2的一个副本
     string s4(n,'c'); 将s4初始化为字符'c'的n个副本
    string的常用操作:
      s.empty()      若为空串,返回true,否则返回false
      s.size()       返回s中字符的个数
    但是注意!!!!!!!!
      string s="ds"+"df";  这样是非法的,不允许


32: class内部的函数优先是使用内联函数的,即使我们自己没写inline,不过要是无法用内联函数就不会用内
     联函数编译了
                       
                                  c++远征之封装篇
33:                     内存分区
      栈区:int x=0;int *p=NULL;
      堆区:int *p=new int;
      全局区:存储全局变量及静态变量
      常量区: string str="hello";
      代码区:存储逻辑代码的二进制
     
34:                          初始化列表
     可以通过初始化列表的方式
      class Student
     {
       public:
             Student():m_strName("Jim"),m_iAge(19) //对于多个数据成员初始化,要用逗号隔开,赋值时
                                             //用括号
              {
                ...
               }
       private:
             string m_strName;
             int m_iAge;   
      };
       初始化列表优先于构造函数执行,即先给数据成员赋值,在调用构造函数,初始化列表只能用于构造函     数,这种方式初始化速度快,效率高,推荐使用这种方式,那么,既然构造函数完全可以做这种工作,为
     什么又要初始化列表呢?仅仅是为了效率高,速度快?不是的,举个例子:
      class Circle
      {
        public:
              Circle(){m_dPi=3.14;} //如果用这种方式初始化,编译器会报错
              Circle():m_dPi(3.14){} //但是初始化列表可以
        private:
              const double m_dPi;
       };         
      圆这个类中,Pi是不变的,因此用const,以后建议这样用
      Student(string name,int age):m_strName(name),m_iAge(age)
      {
          ...
       } 
 
35:                          拷贝构造函数
        class Student
     {
       public:
             Student(string name,int age):m_strName(name),m_iAge(age)
              {
                cout<<" Student(string name,int age):m_strName(name),m_iAge(age)"<<endl;
               }
       private:
             string m_strName;
             int m_iAge;   
      };
      当定义了一个Student类,然后再main函数中:
       Student s1;
       Student s2=s1;
       Student s3(s1);
      这样实例化s1调用的是我们在类中定义构造函数,而s1和s3调用的是拷贝构造函数,因为自己没定义拷贝
      构造函数,所以只会打印一行"Student(string name,int age):m_strName(name),m_iAge(age)",而不是三行;如何定义拷贝函数呢?以这个Student为例:
      定义格式:类名(const 类名 &变量名){ }
        Student(const Student &s)
        {
            cout<<"Student(const Student &s)"<<endl;
         }
       当要传递类实例化的对象的值时就会调用拷贝构造函数,比如定义一个函数void test(Student s){}
      这时由于是值传递,所以会调用拷贝构造函数


36:                       析构函数
     定义格式:~类名(){ }   //不加任何参数


37:                          对象成员
     即类的成员还是类,比如定义一个线段类,两点确定一条线段,所以线段应该有两个表示点的数据成员,     而点也是一个类
 
38:                        深拷贝与浅拷贝
      浅拷贝:只是简单赋值,比如:
      class Array
      {
       public:
              Array(){m_iCount=5;m_pArr=new int[m_iCount];}
              Array(const Array &arr)
              {
                 m_iCount=arr.m_iCount;
                 m_pArr=arr.m_ipArr;
               }<

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值