• C++primer 第二章 变量和基本类型


    昨天思考了一下,感觉明白了。于是报名了软考,还有挑战z杯,想着四级还要不要报,毕竟我也不是有天赋的人,就只能努力去做个努力的人。加油!!! 不知道未来怎么样,那就走好现在吧!!!

    C++中的类型

    C++语言中有多种类型,包括基本数据类型、复合数据类型和用户自定义类型。以下是C++的一些常见类型: 

    1. 基本数据类型(Primitive Data Types):
       - 整数类型:int、short、long、long long、unsigned等。
       - 浮点数类型:float、double。
       - 字符类型:char、wchar_t、char16_t、char32_t。
       - 布尔类型:bool。

    2. 复合数据类型(Compound Data Types)
       - 数组(Array):存储相同类型的多个元素的集合。
       - 结构体(Struct):将不同类型的数据聚集到一个对象中。
       - 联合体(Union):使用相同的内存位置存储不同类型的数据。
       - 枚举(Enum):定义具有离散取值集合的新类型。

    3. 指针类型(Pointer Types):
       - 指针(Pointer):存储内存地址的变量,用于间接访问和修改数据。
       - 空指针(nullptr):表示指针不指向任何有效的内存位置。
       - 空类型指针(void*):指向未知类型的指针。

    4. 引用类型(Reference Types):
       - 引用(Reference):为变量起别名,在声明时使用&操作符。

    5. 常量类型(Constant Types):
       - const:用于声明常量,值不能被修改。
       - constexpr:用于在编译时计算表达式的常量。

    6. 自定义类型(User-defined Types):
       - 类(Class):封装数据和函数的用户定义类型。
       - 枚举类(Enum class):具有强类型和作用域的枚举类型。
       - 联合体(Union):使用相同的内存位置存储不同类型的数据。
       - 结构体(Struct):将不同类型的数据聚集到一个对象中。
       - 类型别名(Typedef):为现有类型创建新的类型名称。
       - using 声明(using declaration):引入命名空间中的特定成员。

    其中bool类型是一个字节,char类型一个字节,wchar_t为宽字符为16个字节。。。

    int整形通常是四个字节,不过在计算中我们通常作为16个字节数。

    类型转换:

    通常是精度较高的类型向较低类型转换可以,反之则不行。

    变量名的作用域

    在C++中,变量的作用域决定了变量在程序中的可见性和生命周期。以下是几种常见的变量作用域及其代码案例:

    1. 全局作用域(Global Scope):
       - 在函数体外部声明的变量具有全局作用域,可以在整个程序中访问。
       - 示例代码:
         ```cpp
         #include
         
         int globalVariable = 10; // 全局变量
         
         void printGlobalVariable() {
             std::cout << "Global variable: " << globalVariable << std::endl;
         }
         
         int main() {
             printGlobalVariable(); // 输出:Global variable: 10
             return 0;
         }
         ```

    2. 块作用域(Block Scope):
       - 在函数、语句块或循环中声明的变量具有块作用域,只能在其所在的块或内层块中访问。
       - 示例代码:
     

    1.      ```cpp
    2.      #include
    3.      
    4.      void printNumber() {
    5.          int number = 5; // 块作用域变量
    6.          std::cout << "Number: " << number << std::endl;
    7.      }
    8.      
    9.      int main() {
    10.          printNumber(); // 输出:Number: 5
    11.          // std::cout << number; // 错误:无法访问printNumber函数中的number变量
    12.          return 0;
    13.      }
    14.      ```

    3. 函数参数作用域(Function Parameter Scope):
       - 函数参数具有函数参数作用域,只能在函数体内部访问。
       - 示例代码:
     

    1.      ```cpp
    2.      #include
    3.      
    4.      void printName(std::string name) {
    5.          std::cout << "Name: " << name << std::endl;
    6.      }
    7.      
    8.      int main() {
    9.          std::string myName = "Alice"; // 局部变量
    10.          printName(myName); // 输出:Name: Alice
    11.          // std::cout << name; // 错误:无法访问printName函数中的name参数
    12.          return 0;
    13.      }
    14.      ```

    4. 类作用域(Class Scope):
       - 在类定义中声明的成员变量具有类作用域,可以在整个类中访问。
       - 示例代码:
     

    1.      ```cpp
    2.      #include
    3.      
    4.      class MyClass {
    5.      public:
    6.          int memberVariable = 20; // 类成员变量
    7.      
    8.          void printMemberVariable() {
    9.              std::cout << "Member variable: " << memberVariable << std::endl;
    10.          }
    11.      };
    12.      
    13.      int main() {
    14.          MyClass obj;
    15.          obj.printMemberVariable(); // 输出:Member variable: 20
    16.          return 0;
    17.      }
    18.      ```

    这些是变量作用域的几个常见示例,每个作用域都有其特定的可见范围和生命周期。正确使用变量的作用域可以提高代码的可读性、避免命名冲突以及有效地管理变量的生命周期。

    引用和指针

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. int b = 10;
    6. int *a=&b;
    7. int** c = &a;
    8. cout << **c<< endl;
    9. return 0;
    10. }

    在代码中*a=&b  a的值等于b的地址,与就是 a的值为&b,*a就是指向a的值的地址的值,就是指向&b位置的值。

    指针和引用的区别

    指针和引用是C++语言中两种不同的机制,它们都可以用于间接操作内存中的值,但是它们之间有以下几个最大的区别:

    1. 指针和引用的定义方式不同:
       - 指针是一个变量,其存储的值为另一个变量的地址,需要使用*(解引用运算符)来获取所指向的值。指针可以为空或NULL,可以被重新赋值指向不同的内存地址。
       - 引用是一个已经存在的变量的别名,一旦被定义,就不能被改变指向其他变量,也不能为空或NULL。

    2. 指针和引用的用途不同:
       - 指针通常用于动态内存分配、数组及链表等数据结构的实现,以及函数参数传递。
       - 引用通常用于函数的返回值、函数参数传递和类的成员变量。

    3. 指针和引用的空间占用不同:
       - 指针在32位系统中通常占用4个字节,在64位系统中通常占用8个字节,而且每次访问指针变量时都需要额外的开销。
       - 引用本身不占用额外的内存空间,它只是原变量的另一个名称,所以访问引用的速度通常比访问指针快。

    4. 指针和引用的空值处理不同:
       - 指针可以为空或NULL,需要在使用时进行判断,否则可能会导致程序崩溃。
       - 引用不能为NULL或空,一旦被定义,就必须指向一个已经存在的变量。

     const限定符

    顶层const:表示指针是一个常量

    底层const:表示指针所指的是一个常量

    1. **顶层 const**:

      • 顶层 const 出现在对象的最顶层,表示对象本身是一个常量。这意味着你不能通过这个指针或引用来修改对象的值,但可以改变指针或引用指向其他对象。
      1. const int x = 5; // x 是一个顶层 const,不可修改
      2. int const y = 10; // 与上面相同,x 和 y 是等价的
      3. const int* ptr = &x; // ptr 是一个指向常量整数的指针,不允许通过 ptr 修改 x 的值

      复制

    2. **底层 const**:

      • 底层 const 出现在对象的底层,表示对象本身可修改,但不能通过这个指针或引用来修改对象的值。
      1. int a = 5;
      2. int const* ptr = &a; // ptr 是一个指向整数常量的指针,a 是可修改的,但不能通过 ptr 修改 a 的值
      3. const int* constPtr = &a; // 同上,ptr 和 constPtr 是等价的
      • 底层 const 在函数参数中常用于指明参数是只读的,从而防止函数内部修改参数的值。
      1. void foo(const int x) {
      2. // 在函数内部,x 是只读的,不能修改它的值
      3. }

    总结一下:

    • 顶层 const 表示对象本身是常量,不能被修改。
    • 底层 const 表示指向的对象是常量,但指针或引用本身可以修改

    constexpr常量表达式

    `constexpr` 是 C++11 引入的关键字,用于声明常量表达式。常量表达式是在编译时就可以计算出结果的表达式,它具有以下特点:

    1. 在编译时求值:常量表达式的值必须在编译时能够确定,不能依赖于运行时的输入或其他动态操作。
    2. 编译时优化:编译器可以对常量表达式进行求值,并在编译期间进行优化,减少运行时的开销。
    3. 用于常量定义:常量表达式可以用于定义常量变量,并在程序中使用。

    使用 `constexpr` 关键字声明常量表达式时,需要满足一定的条件:

    1. 表达式必须是编译时可求值的,不能含有任何可能运行时才能确定的值或操作。
    2. 表达式中只能使用内置类型、字面值、函数调用(如果函数本身也是 `constexpr` 的),以及支持的运算符。
    3. 声明常量表达式的函数本身也要被声明为 `constexpr`。

    下面是一个示例代码,演示了如何使用 `constexpr` 声明和使用常量表达式:

    1. ```cpp
    2. #include
    3. constexpr int square(int x) {
    4.     return x * x;
    5. }
    6. int main() {
    7.     constexpr int radius = 5;
    8.     constexpr int area = square(radius) * 3.14;
    9.     std::cout << "半径为 " << radius << " 的圆的面积是 " << area << std::endl;
    10.     return 0;
    11. }
    12. ```

    在上面的代码中,`square` 函数被声明为 `constexpr`,它接受一个整数参数并返回该整数的平方。在 `main` 函数中,使用 `constexpr` 声明了常量 `radius` 和 `area`,并通过调用 `square` 函数计算圆的面积。由于所有的操作都是在编译时确定的,因此 `area` 的计算也可以在编译期间完成。

    typedef

    类型别名

    typedef 是 C++ 中的一个关键字,用于为类型定义一个新的别名或类型名。通过使用 typedef,可以为已有的类型赋予一个更具描述性的名称,提高代码的可读性和可维护性。

    typedef 的语法形式如下:

    typedef 原类型 新类型名;

    其中,原类型 表示要定义别名的已有类型,新类型名 是所定义的新类型。

    下面是一些 typedef 的常见用法示例:

    1. typedef int myInt; // 将 int 类型定义为 myInt
    2. typedef double Distance; // 将 double 类型定义为 Distance
    3. typedef int* IntPtr; // 将 int* 类型定义为 IntPtr
    4. typedef struct {
    5. int x;
    6. int y;
    7. } Point; // 将匿名结构体定义为 Point
    8. typedef void (*FunctionPtr)(int); // 将函数指针定义为 FunctionPtr,指向接受 int 参数且返回值为 void 的函数

    在上述示例中,我们使用 typedef 分别为 intdoubleint*、匿名结构体以及函数指针定义了新的类型名。使用这些新类型名时,就相当于使用原类型。

    typedef 在 C++ 中广泛用于提高代码的可读性和可维护性。它特别适用于复杂的类型和函数指针的声明,可以避免编写冗长的类型名,并使代码更加清晰易懂。然而,自 C++11 起,还引入了更加灵活和强大的类型别名机制 using,建议在新的代码中使用 using 来替代 typedef。例如,上述示例可以改写为以下形式:

    1. using myInt = int;
    2. using Distance = double;
    3. using IntPtr = int*;
    4. struct Point {
    5. int x;
    6. int y;
    7. };
    8. using FunctionPtr = void (*)(int);

    decltype类型指示符

    `decltype` 是 C++11 中引入的一个类型指示符(type specifier)。它用于从表达式中推导出其类型,并在编译时确定该表达式的类型。

    `decltype` 的语法形式如下:
    decltype(expression)

    其中,`expression` 是一个有效的 C++ 表达式,可以是任意合法的表达式,包括变量、函数调用、运算符操作等。

    `decltype` 主要有两种使用方式:

    1. 推导变量的类型:通过 `decltype` 可以根据变量的初始化表达式来推导出变量的类型。例如:

      

    1.  ```cpp
    2.    int x = 5;
    3.    decltype(x) y;  // 推导出 y 的类型为 int
    4.    ```

       这里 `decltype(x)` 推导出的类型为 `int`,因为变量 `x` 的初始化表达式是整数值 5。

    2. 推导表达式的类型:通过 `decltype` 可以根据表达式来推导出该表达式的类型。例如:

    1.    ```cpp
    2.    int a = 10;
    3.    double b = 5.5;
    4.    auto result = a + b;
    5.    decltype(a + b) sum;  // 推导出 sum 的类型为 double
    6.    ```

       这里 `decltype(a + b)` 推导出的类型为 `double`,因为表达式 `a + b` 的结果是一个浮点数。

    需要注意的是,`decltype` 不会执行表达式,只负责推导表达式的类型。此外,如果表达式是一个变量名而不是一个初始化表达式,`decltype` 推导的类型将是该变量声明时的类型。例如:

    1. ```cpp
    2. int x = 5;
    3. decltype(x) y = x;  // 推导出 y 的类型为 int
    4. ```

    `decltype` 是一个非常有用的类型指示符,可以在编译时获取表达式的类型,并且能够根据变量初始化表达式来推导出变量的类型。它可以用于声明变量、定义函数返回类型等场景,提高代码的可读性和灵活性。

  • 相关阅读:
    “第六十三天”
    如何获得coredump
    【并发编程五】c++进程通信——信号量(semaphore)
    kotlin学习笔记记录
    各种文件对应的文件类型
    linux4.1.15内核移植到野火PRO开发板开发板
    MySQL覆盖索引的含义
    PDF怎么转换成Word?给大家分享三种简单的转换方法
    Qt扫盲-QSqlTableModel理论总结
    13、使用Spring Security进行权限控制
  • 原文地址:https://blog.csdn.net/qq_64200765/article/details/133186672