zoukankan      html  css  js  c++  java
  • c++中的陷阱(二)

    导言###

    程序设计语言中充满陷阱,一不小心就会掉入其中万劫不复,之所以有陷阱,是因为语言的设计细节不符合程序员的直觉
    所以你会发现,语言越高级越注重顺从程序员的直觉。
    c++也有许多陷阱,所谓山不过来,我就过去,因此将c++中易错点、难点集合于此,会不定期更新。
    参考:c++中的陷阱(一)


    控制语句###

    1. 在swtich语句中存在一个普遍的误解,以为程序只会执行匹配的case标号相关联的语句,实际上,程序从该点开始执行,并跨越case边界继续执行其他语句,直到swtich结束或遇到break

    2. 对于switch结构,只能在它的最后一个case标号或default标号后面定义变量,这是为了避免出现代码跳过变量的定义和初始化的情况。如果需要为某个特殊的case定义变量,则可以引入块语句,在该块语句中定义变量,从而保证这个变量在使用前被定义和初始化。

    char c = 'b';
    switch(c){
    case 'b':
      {
        int i = 0;           //right  i定义在语句块中
        cout<<"b"<<endl; 
      }
    case 'c':
      cout<<"c"<<endl;
    default:
      ;
    }
    
    char c = 'b';
    switch(c){
    case 'b':
      int i = 0;           //error
      cout<<"b"<<endl; 
    case 'c':
      cout<<"c"<<endl;
    default:
      ;
    }
    
    1. do-while语句中,任何在循环条件中引用的变量都必须在do语句之前就已经存在
    string input;
    do{
      cout<<input<<endl;
      cin >> input;
    }while(input != "bye");   //right
    
    do{
      string input;
      cout<<input<<endl;
      cin >> input;
    }while(input != "bye");   //error 变量input只存在于花括号的块作用域中
    
    while(bool status = true){   //right
      cout<<"hello"<<endl;
    }
    
    do{
      cout<<"hello"<<endl;
    }while(bool status = true);   //error 变量status必须在do语句之前就已经存在
    

    函数###

    1. 返回值为void的函数,return后一般不能接表达式,但有一个例外,即返回另一个返回类型同样是void的函数的调用结果
    void func1(){}
    void func2(){return func1();}  //right
    int main(){
      func2();
      return 0;
    }
    
    1. 函数的返回值是引用类型时,谨记不能返回局部对象的引用。因为在函数执行完毕时,将释放分配给局部对象的存储空间,此时,对局部对象的引用就会指向不确定的内存

    2. 函数的返回值是指针时,谨记不能返回局部对象的指针,理由同上

    3. 返回引用的函数返回一个左值,因此可以给返回的引用赋值

    int &func(int &i){return i;}
    int main(){
      int ival = 0;
      cout<<ival<<endl;   // 0
      func(ival) = 1;     //func返回引用,因此返回的是一个左值
      cout<<ival<<endl;   // 1
      return 0;
    }
    
    1. const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用他们调用非const成员函数,则是错误的

    2. 区分重载与非重载
      非重载

    int func(const int i);
    int func(int i);
    int func(int *const i);
    int func(int *i);
    
    typedef int integer;
    int func(int i);
    int func(integer i);
    
    void fun(int i=0);
    void fun(string s="");
    

    重载

    int func(const int &i);
    int func(int &i);
    
    int func(const int *i);
    int func(int *i);
    
    1. 重载函数的实参类型转换
    int func(int i){ cout<<"int func"<<endl;}
    int func(unsigned char){ cout<<"unsigned char func"<<endl;}
    int main(){
      char c = 'a';
      func(c);	 //打印 int func
    }
    /*
    char类型到int型是类型提升,char类型到unsigned char类型是类型转换,在实参匹配时类型提升优于类型转换
    实参类型的转换等级:1.精确匹配 2.通过类型提升 3.通过标准转换 4.通过类类型转换
    */
    
    int func(int i, int ii){ cout<<"int func"<<endl;}
    int func(double d, double dd){ cout<<"double func"<<endl;}
    int main(){
      int i=0;
      double d=0.0;
      func(i,d);		//error 二义性
    }
    /*
    在调用重载函数时,编译器会试图寻找最佳匹配,若无法确定唯一的最佳匹配,则报错
    */
    
    enum ABC {a, b, c};
    int func(ABC val){}
    int main(){
      ABC v = a;
      func(v);      //right
      func(1);	//error 不能直接将整数值作为枚举类型的实参
    }
    
  • 相关阅读:
    Max History CodeForces
    Buy a Ticket CodeForces
    AC日记——字符串的展开 openjudge 1.7 35
    AC日记——回文子串 openjudge 1.7 34
    AC日记——判断字符串是否为回文 openjudge 1.7 33
    AC日记——行程长度编码 openjudge 1.7 32
    AC日记——字符串P型编码 openjudge 1.7 31
    AC日记——字符环 openjudge 1.7 30
    AC日记——ISBN号码 openjudge 1.7 29
    AC日记——单词倒排 1.7 28
  • 原文地址:https://www.cnblogs.com/moonlight-chao/p/3642744.html
Copyright © 2011-2022 走看看