zoukankan      html  css  js  c++  java
  • 《Thinking in C++》学习笔记(二)【第三章】

    第三章 C++中的C

    3.4.4 指针简介

           ‘&’运算符:只要在标识符前加上‘&’,就会得出标识符的地址。

           C和C++有一个专门存放地址的变量类型。这个变量类型叫做指针(pointer)。

           int* ipa,ipb,ipc;    //只有ipa是指针,ipb和ipc是一般的int

           要通过指针访问变量,可以使用以前定义指针使用的同样的运算符来间接引用这个指针 *ipa=100;

    3.4.6C++引用简介

           C++增加了另外一种给函数传递地址的途径,这就是”按引用传递“(pass-by-reference)

           带引用的函数调用仅仅比带指针的函数调用在语法上更清晰,它和指针完成同样的任务:允许函数去改变外部对象。

    3.4.7用指针和引用作为修饰符

           如果声明指针是void*,它意味着任何类型的地址都可以引用那个指针

           一旦我们间接引用一个void*,就会丢失关于类型的信息,在使用前必须转换为正确的类型;

    //VoidPointer.cpp
    int main()
    {
       void* vp;
       char v; int i; float f; double d;
       //The address of ANY type can be assiged to a void pionter;
        vp=&c;  vp=&i;
        vp=&f;   vp=&d;
    }

    //CastFromVoidPointer
    int main()
    {
    int i=99;
    void* vp=&i;
    //Can't dereference a void pointer
    //*vp=3; //Compile-time error
    //Must cast back to int before dereferencing;
    *((int*)vp)=3;
    }

    3.5作用域

           作用域告诉我们一个变量的有效范围,在哪里创建,在哪里销毁。变量的有效作用域从它的定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号。也就是说,作用域由变量所在的最近一对括号确定。

           作用域可以嵌套,即可以在所处的作用域内访问外层作用域的一个变量。

    3.5.1实时定义变量

           C语言强制在作用域的开始就定义所有变量,以便在编译器创建一个块时,能给所有这些变量分配空间。

           C++允许在作用域的任何地方定义变量,还可以在for循环和while循环的控制表达式内定义变量,在if的条件表达式和swith的选择器语句内定义变量。

    3.6指定存储空间分配

            创建一个变量时我们拥有指定变量生存期限的很多选择,指定怎样给变量分配存储空间。

    3.6.1全局变量

            全局变量是在所有函数体外部定义的,程序的所有部分甚至其它文件中的代码也可以使用它。

    3.6.2局部变量

            局部变量经常称为自动变量(automatic variable),因为它们在进入作用域时自动生成,离开作用域后自动消失。

    3.6.2.1寄存器变量

            寄存器变量是一种局部变量,不能有全局的或静态的register变量,register变量是有限制的,不能得到register变量的地址。

    3.6.3静态变量

            通常函数中定义的局部变量在函数作用域结束时消失,当再次调用这个函数时会重新创建该变量的存储空间,其值会被重新初始化。如果想再整个程序的生命期里保持这个局部变量的值,可以定义函数的局部变量为static(静态的),初始化只在第一次调用时执行。

             static还具有文件作用域(file scope),即变量是局部与文件的,在文件的外部不可以使用这个名字。

    //Using a static variable in a function
    #include<iostream>
    using namespce std;
    
    void func(){
       static int i=0;
       cout<<"i="<<i++<<endl;
    }
    
    int mian(){
       for(int x=0;x<10;x++)
         func();
    }

    3.6.4.1连接

            内部连接(internal linkage)意味着只对正在编译的文件创建一片单独的存储空间。用内部连接,别的文件可以使用相同的标示符或全局变量,连接器不会发生冲突——也就是为每一个标示符创建单独的存储空间,在C/C++中,内部连接由关键词static指定。

            外部连接意味着为所有编译过的文件创建一片单独的存储空间。一旦存储空间创建,编译器必须解决所有对这片存储空间的引用。全局变量和函数名有外部连接。通过关键字extern声明,可以从其它文件访问这些变量和函数。函数之外定义的所有变量(在C++中除了const)和函数定义默认为外部连接,可以使用关键字static特地强制它们具有内部连接。

            调用函数时,自动(局部)只是临时存在于堆栈中,连接器不知道自动变量,所以这些变量没有连接。

    3.6.5常量

            C++引入了命名常量的概念,命名常量就像变量一样,只是它的值不能改变。可以在参数列表中使用命名常量,即使列表中的参数是指针或引用(可以获得const的地址),const就像正常变量一样有作用域。

    3.6.5.1常量值

            C++中,一个const必须有初始值。

    3.6.6 volatile变量

            限定词volatile告诉编译器“不知道何时会改变”,防止编译器依据变量的稳定性做任何优化。

    3.7.2.1预处理宏介绍

            #define的缺点:  (1)不支持类型检查      (2)不考虑作用域     (3)符号名不能限制在一个命名空间中,用宏名中的参数带入语句中的参数

            #define Print(Var, digits)  count << setw(digits) << (Var) << endl       //宏后面没有;号

                                                                                                                 //Print(Var)中的Print和(之间不能有空格,否则(就会被解释为置换字符串的一部分调用

            Print(ival, 15);

            预处理器就会把它换成

            cout << setw(15) << (ival) << endl;

    3.7.6移位运算符

            左移运算符(<<)引起运算符左边的操作数向左移动,移动的位数由运算符后面的操作数指定。右移运算符类似。 

    //Display a byte in binary
    #include<iostream>
    void printBinary(const unsigned char val){
        for(int i=7;i>=0;i--)
          if(val & (1<<i))
              std::cout<<"1";
          else
              std::cout<<"0";
    }

    3.7.12 C++的显式转换

    3.7.12.1静态转换(static_cast)

            典型的非强制转换、窄化变换(narrowing conversion)、使用viod*的强制装、隐式类型转换

    3.7.12.2常量转换(const_cast)

            如果从const转换为非const或从voletile转换为volatile,可以使用cont_cast。

    3.7.12.3重解释转换(reinterpret_cast)

    3.7.14 asm关键字

            这是一种转义(escape)机制,允许在C++程序中写汇编代码。

    3.8.3用enum提高程序清晰度

            enum关键字通过为所给出的任何标示符赋值0、1、2等值来自动地列举出它们。

            枚举类型检查

    3.8.4用union节省空间

            有时程序会用同一个变量处理不同的数据类型。union把所有的数据放进一个单独的空间内,它计算出放在union中的最大项所需的空间,并生成union的大小。

    3.9调试技巧

    3.9.1.1预处理器调试标记

    3.9.1.2运行期调试标记

    3.9.2把变量和表达式转换成字符串

    3.9.3 C语言assert()宏

    3.10函数地址

    3.10.1定义函数指针

            void (*funcPtr) (); //从变量名开始,“右-左-右...”动作方式

    3.10.3使用函数指针

            函数func()的地址是由没有参数列表的函数名(func)产生的,也可以用更加明显的语法&func()。为了调用这个函数,应当用与 声明函数相同的方法间接引用指针。

    //Defining and using a pointer to a function
    #include<iostream>
    using namespace std;
    
    void func(){
      cout<<"func() called ..."<<endl;
    }
    
    int main(){
      void (*fp) ();  //Define a function pointer
      fp=func;    //Initialize it
      (*fp) ();
      void (*fp2) ()=func;
      (*fp2) ();
    }

            

             

  • 相关阅读:
    构建之法阅读笔记04
    学习进度条10
    描绘用户场景并将典型用户和用户场景描述
    学习进度条09
    构建之法阅读笔记03
    学习进度条08
    每日站立会议10(完成)
    每日站立会议09
    团队成员细节工作项估计
    JS实现全选、不选、反选
  • 原文地址:https://www.cnblogs.com/sage-blog/p/3858748.html
Copyright © 2011-2022 走看看