C++ 关键字与库函数 学习总结

sizeof与strlen

  • 含义
    • sizeof:是一个操作符,用于计算数据类型或变量的大小(以字节为单位)。在编译时求值
    • strlen: 是一个函数,用于计算字符串的长度(不包括终止符 '\0')。在运行时求值
  • 不同点
    • 计算时间strlen是库函数,程序运行时计算长度;sizeof则是在编译时计算长度
    • 计算方式:sizeof包括终止符号 \0 。strlen则不包括,只计算字符串的实际长度
  • 两者的返回类型都是size_t类型

#include <stdio.h>int main() {int a = 10;double b = 20.0;char c = 'A';char str[] = "Hello, World!";printf("Size of int: %zu bytes\n", sizeof(a));              // 输出变量 a 的大小printf("Size of double: %zu bytes\n", sizeof(b));          // 输出变量 b 的大小printf("Size of char: %zu bytes\n", sizeof(c));            // 输出变量 c 的大小printf("Size of string: %zu bytes\n", sizeof(str));        // 输出数组 str 的大小,包括终止符 '\0'return 0;
}

#include <stdio.h>
#include <string.h>int main() {char str[] = "Hello, World!";printf("Length of string: %zu characters\n", strlen(str));  // 输出字符串 str 的长度,不包括终止符 '\0'return 0;
}

 static

C和C++中都可以用static去定义静态变量以及静态函数,因为C++是面向对象编程,所以还可以使用static去定义静态成员变量以及静态成员函数等。

static全局和局部静态变量

static 全局静态变量

  • 全局静态变量是在文件范围内定义的,并且只能在定义它的文件中访问。它在程序的整个生命周期内都存在,但它的作用域仅限于定义它们的文件
  • static全局静态变量,则只可以在定义所在文件中有效,同一个程序中的其他源文件不可以使用。

static局部静态变量

  • 局部静态变量是在函数内部定义的,并且只能在定义它们的函数中访问
  • 存储在静态存储区中,生命周期是贯穿在整个程序的运行期间

static全局静态变量和static局部静态变量区别总结 

  • 作用域

    • 全局静态变量:仅限于定义它的文件中
    • 局部静态变量:仅限于定义它们的函数
  • 生命周期

    • 全局静态变量:在程序的整个生命周期内都存在。
    • 局部静态变量:在程序的整个生命周期内都存在,但它的值在函数调用之间保留
  • 存储位置

    • 全局静态变量:存储在静态数据区
    • 局部静态变量:存储在静态数据区,而不是栈区
    • 两者都存储静态数据区中

// 全局静态变量
static int global_static_var = 0;void increment_global_static_var() {global_static_var++;printf("全局静态变量: %d\n", global_static_var);
}int main() {increment_global_static_var(); // 输出:1increment_global_static_var(); // 输出:2return 0;
}

 

#include <stdio.h>void increment_local_static_var() {// 局部静态变量static int local_static_var = 0;local_static_var++;printf("局部静态变量: %d\n", local_static_var);
}int main() {increment_local_static_var(); // 输出:1increment_local_static_var(); // 输出:2increment_local_static_var(); // 输出:3return 0;
}

static静态函数 

 static静态函数

  • 作用域:只可以在定义该函数的文件内部调用,不可以从其他文件中访问该函数
  • 作用:定义的函数只放在该文件中使用,避免命名造成的冲突

 代码说明:两段代码是放在不同的文件

static静态成员变量 

static静态成员变量

  •  声明:类内声明,类外定义初始化。可以通过类名直接访问,不需要创建对象
  • 作用域:静态成员变量在整个进程生命周期内都存在
  • 特点
    • 共享性:所有类对象共享一个静态成员变量
    • 静态成员变量可以作为成员函数的参数,普通成员变量不可以
    • 静态成员变量的类型可以用该类自己的类型,而普通成员变量只可以用该类的指针或者引用
    • 唯一性:无论创建多少对象,静态成员变量在内存中只占用同一块内存空间

#include <iostream>class MyClass {
public:// 静态成员变量声明static int staticVar;// 成员函数,用于显示静态成员变量的值void display() const {std::cout << "Static Variable: " << staticVar << std::endl;}
};// 静态成员变量定义(注意记忆)
int MyClass::staticVar = 0;int main() {// 通过类名访问静态成员变量MyClass::staticVar = 5;MyClass obj1;MyClass obj2;obj1.display(); // 输出:Static Variable: 5obj2.display(); // 输出:Static Variable: 5// 修改静态成员变量的值MyClass::staticVar = 10;obj1.display(); // 输出:Static Variable: 10obj2.display(); // 输出:Static Variable: 10return 0;
}

 static静态成员函数

static静态成员函数

  •  作用域:静态成员函数是没有this指针的,所以不可以调用非静态成员或者非静态成员函数,可以类内声明类外定义
  • 特点
    • 静态成员函数是类作用域的全局函数
    • 静态成员函数不可以声明成virtual const volatile函数
    • 独立:静态成员函数是独立于任何对象的,因为不可以访问类的非静态成员变量或非静态成员函数
  • 优点
    • 静态成员中可以封装与对象无关的逻辑,从而实现类内共享
    • 静态成员函数不需要创建对象就可以调用,所以可以节省内存资源

#include <iostream>class MyClass {
public:// 静态成员函数声明static void staticFunction();// 非静态成员函数声明void nonStaticFunction() {std::cout << "This is a non-static member function.\n";}private:int nonStaticVar; // 非静态成员变量
};

  static对象

 static对象

  • 静态全局对象:整个程序运行期间存在,但是其作用域只限于定义它的文件中
  • 静态局部对象:函数内定义,只可以在定义它的作用域中访问,第一次调用的时候初始化,在程序的整个生命周期都保留该数值,不会再次初始化。
  • 类的静态成员对象:每个类只拥有一个静态成员对象的实例,并且所有对象共享这个对象
#include <iostream>static int globalStaticVar = 0; // 静态全局对象void incrementGlobalStaticVar() {globalStaticVar++;std::cout << "Global static variable: " << globalStaticVar << std::endl;
}int main() {incrementGlobalStaticVar(); // 输出:Global static variable: 1incrementGlobalStaticVar(); // 输出:Global static variable: 2return 0;
}
#include <iostream>void incrementLocalStaticVar() {static int localStaticVar = 0; // 静态局部对象localStaticVar++;std::cout << "Local static variable: " << localStaticVar << std::endl;
}int main() {incrementLocalStaticVar(); // 输出:Local static variable: 1incrementLocalStaticVar(); // 输出:Local static variable: 2incrementLocalStaticVar(); // 输出:Local static variable: 3return 0;
}
#include <iostream>class MyClass {
public:static MyClass staticInstance; // 静态成员对象声明void display() const {std::cout << "This is a static member object." << std::endl;}
};// 静态成员对象定义
MyClass MyClass::staticInstance;int main() {MyClass::staticInstance.display(); // 通过类名访问静态成员对象MyClass obj;obj.staticInstance.display(); // 通过对象访问静态成员对象(不推荐)return 0;
}

const

总结:

  • const常量:const修饰变量或者成员变量,可以进行类型检查,从而节省内存空间提高效率
  • const函数参数:传递过来函数参数的数值不可以改变
  • const成员函数:该成员函数不可以修改任何类型的成员变量(mutable修饰的变量可以),同时该函数不可以调用非const的成员函数

const 变量

const 变量

  • 全局const变量:整个程序色生命周期存在,不可以修改,其他文件通过extern声明也可以访问
  • 局部const变量:函数或代码块中定义,只可以在定义的作用域中访问
  • 类的const成员变量:类中声明的const成员变量,必须在构造函数初始化列表中进行初始化
#include <iostream>const int globalConstVar = 100; // 全局 const 变量int main() {std::cout << "全局 const 变量: " << globalConstVar << std::endl;// globalConstVar = 200; // 错误:不能修改 const 变量return 0;
}
#include <iostream>void displayLocalConst() {const int localConstVar = 50; // 局部 const 变量std::cout << "局部 const 变量: " << localConstVar << std::endl;// localConstVar = 100; // 错误:不能修改 const 变量
}int main() {displayLocalConst();return 0;
}
#include <iostream>class MyClass {
public:const int memberConstVar; // 类的 const 成员变量MyClass(int val) : memberConstVar(val) {} // 在构造函数初始化列表中初始化void display() const {std::cout << "类的 const 成员变量 " << memberConstVar << std::endl;}
};int main() {MyClass obj(10);obj.display();// obj.memberConstVar = 20; // 错误:不能修改 const 成员变量return 0;
}

const指针和指向const的指针

const指针和指向const的指针

  • 指向const的指针:指针指向的值不可以通过指针对该值进行修改,但是指针本身可以改变
  • const指针:指针本身是常量,不能够改变指向,但是指向的数值可以修改
  • 指向const的const指针:指针本身和指针指向都不可以修改
  • 注意:两种写法不同,注意记忆

#include <iostream>int main() {int value = 30;const int* ptr = &value; // 指向 const 的指针std::cout << "Value: " << *ptr << std::endl;// *ptr = 40; // 错误:不能通过 ptr 修改值int anotherValue = 50;ptr = &anotherValue; // 可以改变指针本身std::cout << "Another value: " << *ptr << std::endl;return 0;
}
#include <iostream>int main() {int value = 30;int* const ptr = &value; // const 指针std::cout << "Value: " << *ptr << std::endl;*ptr = 40; // 可以修改指向的值std::cout << "Modified value: " << *ptr << std::endl;// int anotherValue = 50;// ptr = &anotherValue; // 错误:不能改变指针本身return 0;
}
#include <iostream>int main() {int value = 50;const int* const ptr = &value; // 指向 const 的 const 指针std::cout << "Value: " << *ptr << std::endl;// *ptr = 60; // 错误:不能修改指向的值// int anotherValue = 70;// ptr = &anotherValue; // 错误:不能改变指针本身return 0;
}

const引用 

const引用:const引用指向const对象的应用,可以读取变量,但是不可以通过应用修改指向的数值

#include <iostream>void display(const int& ref) {std::cout << "Reference: " << ref << std::endl;// ref = 20; // 错误:不能通过 const 引用修改值
}int main() {int value = 10;display(value);return 0;
}

define 和 const

define 和 const

  • 含义
    • #define 是一个预处理指令,用于定义宏。编译之前,预处理器会用宏的值替换程序中的所有宏名。没有类型检查,也不会在调试信息中出现
    • const 是一个关键字,用于定义类型安全的常量变量。const 变量在程序运行期间受类型检查,并且可以用于更复杂的数据类型,如数组、指针和对象
  • 特点:
    • 编译阶段:define是在编译预处理阶段进行替换,没有时间开销。const则是在编译阶段确定数值,会有时间开销。
    • 安全性:define只是进行简单的代码替换,不会进行类型安全检查;const定义的常量是由类型,所以会进行类型安全检查
    • 存储空间:define浪费空间,程序每次替换的时候都会在内存中备份,替换越多备份越多 ;const节省空间,因为存储在静态区。
    • 调试:define定义的宏不可以调试,预编译阶段已经替换了。const定义的常量可以进行调试
    • define可以接受参数构造复杂的表达式,const不可以接受参数构造复杂的表达式。

inline

  • 含义
    • inline关键字用于提示编译器将函数定义为内联函数,内联函数的目的在于减少函数调用的开销从而提高程序的运行效率
    • 内联函数代码会在每次调用的时候直接插入到调用点,避免函数调用不必要的开销,内联只是一个建议,编译器可以选择忽略它
  • 特点
    •  减少函数调用开销:inline是一个关键字,像普通的函数一样被调用,而不是直接在调入点直接展开,从而减少调用函数带来的开销,提高程序运行效率
  • 使用
    • 类内定义成员函数默认就是内联函数,虚函数除外(虚函数运行时决定,编译时无法确定的虚函数的实际调用)
    • 类外定义成员函数,需要加上inline关键字

 

#include <iostream>class MyClass {
public:inline void display() {std::cout << "内联函数运行" << std::endl;}
};int main() {MyClass obj;obj.display();return 0;
}

new  malloc  delete free

malloc 

malloc 

  • 含义:该库函数用于动态分配内存,运行的时候从堆内存中分配指定大小的字节,并返回指向该内存块的指针。malloc分配的内存未初始化,所以内部的数据不确定

原理分析

  • 进程启动后,操作系统会给该进程分配一个初始的堆区域,同时初始化一个数据结构(此处按照链表梳理)
  • 第一次调用malloc的时候,内存管理器再空闲链表中查找一个足够大的空间,然后分配,如果失败则返回null
  • 是进程调用free的时候,内存管理器释放该链表所占用的内存空间

#include <stdio.h>
#include <stdlib.h>int main() {int* ptr;ptr = (int*)malloc(10 * sizeof(int)); // 分配10个整数大小的内存if (ptr == NULL) {printf("Memory allocation failed\n");return 1;}for (int i = 0; i < 10; i++) {ptr[i] = i * 10;}for (int i = 0; i < 10; i++) {printf("%d ", ptr[i]);}free(ptr); // 释放内存return 0;
}

new 和 malloc的区别 

new 和 malloc的区别

  • 初始化:new申请内存时,会调用对象的构造函数,然后对对象初始化;malloc会在堆中申请一块指定大小的内存空间,仅分配内存,不会初始化
  • new指定内存空间初始化对象,malloc只可以在堆中申请内存
  • new是C++的操作符malloc是C中的一个函数
  • 返回值:new返回值是一个对象的指针类型malloc则返回void*指针
  • 空间大小:new的空间大小是由编译器自动计算的,malloc是需要指定其空间大小new的空间大小不可以改变

#include <iostream>class MyClass {
public:MyClass() {std::cout << "Constructor called" << std::endl;}~MyClass() {std::cout << "Destructor called" << std::endl;}
};int main() {// 使用 new 分配单个对象MyClass* obj = new MyClass();// 使用 delete 释放内存delete obj;// 使用 new 分配数组MyClass* arr = new MyClass[3];// 使用 delete[] 释放数组内存delete[] arr;return 0;
}

#include <iostream>
#include <cstdlib>class MyClass {
public:MyClass() {std::cout << "Constructor called" << std::endl;}~MyClass() {std::cout << "Destructor called" << std::endl;}
};int main() {// 使用 malloc 分配内存MyClass* obj = (MyClass*)malloc(sizeof(MyClass));// 需要手动调用构造函数new (obj) MyClass(); // 使用定位 new 调用构造函数// 使用 free 释放内存前需要手动调用析构函数obj->~MyClass();free(obj);// 使用 malloc 分配数组MyClass* arr = (MyClass*)malloc(3 * sizeof(MyClass));// 需要手动调用构造函数for (int i = 0; i < 3; ++i) {new (&arr[i]) MyClass(); // 使用定位 new 调用构造函数}// 使用 free 释放数组内存前需要手动调用析构函数for (int i = 0; i < 3; ++i) {arr[i].~MyClass();}free(arr);return 0;
}

delete和free的区别 

delete和free的区别

  • delete是C++的一个操作符,可以进行重载;free是C中的一个函数,不可以进行重载
  • free只会释放指向的内存,不会执行对象的析构函数;delete则可以执行对象的析构函数
  • delete和delete[ ] 
    • 释放 newnew[ ]分配的内存
    • 适当new分配的单个对象,释放new[ ] 分配的数组
  • free
    • 用法:释放malloc 、calloc 、realloc分配的内存
    • 仅释放内存,不调用析构函数

volatile

含义

  • 该关键字用于修饰变量,告诉编译器该变量在程序运行期间可能被改变,因为贬义词不能够对这个变量进行优化,需要每次访问该变量的时候都重新获取其数值

volatile的作用

  • 阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回
  • 阻止编译器调整操作volatile变量的指令排序

volatile使用场景分析

  •  多线程编程:volatile变量可以被多个线程修改,使用该关键字从而确保每个线程从内存中读取最新的数值,而不是从寄存器或者缓存中读取的旧值

限制

  • 非线程安全:该关键字可以确保每次读取变量的时候都是从内存中获取的最新值,但是不保证其原子性,所以在多线程中,需要使用互斥锁或者原子操作来保证其线程安全
  • 不适合硬件优化:如果CPU缓存或者其他硬件优化,则需要使用其他方式,内存栅栏(memory barriers)或 C++11 中的 std::atomic
//多线程场景下的使用#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>volatile bool stopFlag = false;void worker() {while (!stopFlag) {std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cout << "Worker thread exiting." << std::endl;
}int main() {std::thread t(worker);std::this_thread::sleep_for(std::chrono::seconds(1));stopFlag = true;t.join();return 0;
}

使用宏实现比较大小以及两个数的最小值

#include <iostream>
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
using namespace std;int main ()
{int var1 = 10, var2 = 100;cout << MAX(var1, var2) << endl; //100cout << MIN(var1, var2) << endl; //10return 0;
}

 宏定义和内联函数的区别 

 宏定义和内联函数的区别

  • 内联函数在编译的时候展开,宏则在编译预处理的时候展开;
  • 内联函数展开后是嵌入到代码中,宏只是进行简单的文本替换
  • 内联函数是真正的函数会对参数类型以及语句进行检查
  • 内联函数在调用点直接展开避免函数参数压栈,减少开销
  • 宏只是简单的对文本进行替换,所以容易出错
  • 内联函数可以调试宏函数无法调试

使用场景分析

  • 宏:定义简单的常量和轻量级的宏功能,负责的宏避免使用
  • 内联函数:内联函数比宏更安全且容易调试和维护

C和C++中的struct区别

含义

  • C语言中:struct 主要用于将多个不同类型的数据组合在一起形成一个复合数据类型。结构体中的成员默认是公开的(public),但它们不支持方法、构造函数、析构函数和访问控制
  • 在C++ 中:struct 保留了 C 中的所有特性,但它增加了许多新的功能,使其更接近于类(class)。在 C++ 中,struct 可以包含成员函数、构造函数、析构函数、访问控制和继承等特性。默认情况下,struct 的成员是公开的(public),而 class 的成员是私有的(private)

两者区别总结

  • 数据类型不同:C语言中是用户自定义的数据类型,C++中则是抽象数据类型,支持成员函数定义
  • 访问权限不同:C语言中的没有访问权限设置,不能够定义成员函数;C++中的struct和类一样,由访问权限可以定义成员函数
  • 定义变量:C语言中定义struct类型的变量时,需要加上struct关键字,但是C++ 中的struct可以不加关键字
  • 继承与多态:C++中的可以继承也可以对应实现多态

struct与union区别

  • 内存空间:union联合体中的所有变量共享同一段内存空间,struct中的每个成员变量独占内存空间
  • 成员:联合体只有一个有效成员(内部是有多个不同数据成员组成),结构体中的所有成员都有效
  • 成员赋值:联合体不同成员赋值的时候,会覆盖其他成员的值,但是对于结构体给不同成员赋值,则不会影响
  • 内存大小:联合体的大小是所有变量的最大值,按照最大值类型的倍数进行分配大小;结构体则是按照内存对齐原则
  • struct可以定义变长数组成员变量 int a [] ,union中不可以包含这种不确定长度的变量

//struct
#include <stdio.h>struct Point {int x;int y;
};int main() {struct Point p;p.x = 10;p.y = 20;printf("Point: (%d, %d)\n", p.x, p.y);return 0;
}

//union事例
#include <stdio.h>union Data {int i;float f;char str[20];
};int main() {union Data data;data.i = 10;printf("data.i: %d\n", data.i);data.f = 220.5;printf("data.f: %f\n", data.f);// 注意:此时访问 data.i 会得到未定义的值printf("data.i: %d\n", data.i); // 由于 union 共用内存,data.i 的值已被 data.f 覆盖return 0;
}

//混合使用
#include <stdio.h>struct Mixed {int type;union {int intValue;float floatValue;char strValue[20];} data;
};int main() {struct Mixed m;m.type = 0; // 表示 int 类型m.data.intValue = 10;printf("Type: %d, IntValue: %d\n", m.type, m.data.intValue);m.type = 1; // 表示 float 类型m.data.floatValue = 220.5;printf("Type: %d, FloatValue: %f\n", m.type, m.data.floatValue);m.type = 2; // 表示字符串类型snprintf(m.data.strValue, 20, "Hello, World!");printf("Type: %d, StrValue: %s\n", m.type, m.data.strValue);return 0;
}

extern C的作用

含义

  • extern C是一个链接规范,指示编译器按照C语言的方式处理被包含的代码
  • 目的是解决C++和C兼容性的问题,尤其在链接阶段
  • 让C++编译器生成与C兼容的符号名,从而让C++代码可以调试C代码

事例(一个用C写的函数,一个CPP代码,采用C的方式连接)

// c_code.c
#include <stdio.h>void c_function() {printf("This is a C function.\n");
}
// cpp_code.cpp
#include <iostream>// 告诉编译器按 C 语言的方式链接 c_function
extern "C" void c_function();int main() {c_function();return 0;
}

strcpy函数缺陷

  • 作用
    • C++中的一个标准函数,其会将函数' \0' 结束符的字符串复制到另一个地址空间,返回值的类型为char*,返回值为拷贝后的字符串首地址
  • 缺陷
    • 缓冲区溢出:不检查目的缓冲区的大小边界,而是将源字符串逐一全部复制到到新内存空间中,同时加上字符串的终止符号,但是这种行为会导致其他变量被覆盖
    • 不安全复制:如果源字符串没有以空字符 \0 结尾,那么strcpy就会一直复制,直到内存中的随机空字符
  • 避免缺陷
    • 使用strncpy 代替
      • strcpy的安全版本,允许指定最大复制的字符数,从而防止缓冲区的溢出
      • 如果源字符串长度大于指定的最大字符数,目标字符串将不会自动添加空字符
    • 动态内存分配

#include <stdio.h>
#include <string.h>int main() {char src[] = "This is a long string that will not cause buffer overflow";char dest[10];strncpy(dest, src, sizeof(dest) - 1);dest[sizeof(dest) - 1] = '\0'; // 确保目标字符串以空字符结尾printf("Destination: %s\n", dest);return 0;
}

lambda 表达式

  • capture:用于捕获外部变量,可以按值捕获(=)或按引用捕获(&)。
  • parameters:函数参数列表,与普通函数相同。
  • return_type:返回类型(可选,如果编译器能推断出返回类型,则可以省略)。
  • function body:函数的具体实现

 基本lambda表示使用

#include <iostream>int main() {auto add = [](int a, int b) -> int {return a + b;};int result = add(3, 4);std::cout << "Result: " << result << std::endl;return 0;
}

 捕捉外部变量

#include <iostream>int main() {int x = 10;int y = 20;// 按值捕获(复制变量)auto addValueCapture = [x, y]() {return x + y;};// 按引用捕获(引用变量)auto addReferenceCapture = [&x, &y]() {return x + y;};std::cout << "Value Capture: " << addValueCapture() << std::endl;std::cout << "Reference Capture: " << addReferenceCapture() << std::endl;return 0;
}

 捕捉所有外部变量

#include <iostream>int main() {int x = 10;int y = 20;// 按值捕获所有外部变量auto addAllValueCapture = [=]() {return x + y;};// 按引用捕获所有外部变量auto addAllReferenceCapture = [&]() {return x + y;};std::cout << "All Value Capture: " << addAllValueCapture() << std::endl;std::cout << "All Reference Capture: " << addAllReferenceCapture() << std::endl;return 0;
}

实现排序 

#include <algorithm>
#include <iostream>
#include <vector>int main() {std::vector<int> numbers = {5, 2, 9, 1, 5, 6};// 使用 lambda 表达式进行升序排序std::sort(numbers.begin(), numbers.end(), [](int a, int b) {return a < b;});std::cout << "Sorted numbers: ";for (int n : numbers) {std::cout << n << " ";}std::cout << std::endl;return 0;
}

C++14 

C++14,lambda函数形参允许泛型和初始化捕捉

 C++14中,lanbda表达式支持泛型参数,从而使得可以编写类型无关的lambda表达式

#include <iostream>
#include <vector>
#include <algorithm>int main() {auto add = [](auto a, auto b) {return a + b;};std::cout << "Sum of integers: " << add(1, 2) << std::endl; // 输出 3std::cout << "Sum of doubles: " << add(1.5, 2.3) << std::endl; // 输出 3.8std::cout << "Concatenation of strings: " << add(std::string("Hello, "), std::string("World!")) << std::endl; // 输出 Hello, World!return 0;
}

初始化捕捉:允许在捕获列表中直接初始化捕获的变量。主要作用在于捕捉并初始化一个新的变量时无需定义一个临时变量 

#include <iostream>int main() {int x = 10;int y = 20;auto lambda = [z = x + y]() {std::cout << "Captured sum: " << z << std::endl;};lambda(); // 输出 Captured sum: 30return 0;
}

explicit

explicit关键字用于C++的构造函数中,用于防止隐式转换

#include <iostream>
using namespace std;class MyClass {
public:explicit MyClass(int value) : m_value(value) {}void printValue() const {cout << "Value: " << m_value << endl;}private:int m_value;
};void display(MyClass obj) {obj.printValue();
}int main() {MyClass obj1(10); // 正确,显式调用构造函数obj1.printValue();// MyClass obj2 = 20; // 错误,隐式转换被explicit阻止MyClass obj2 = MyClass(20); // 正确,显式调用构造函数obj2.printValue();display(obj1); // 正确,显式调用// display(30); // 错误,隐式转换被explicit阻止display(MyClass(30)); // 正确,显式调用构造函数return 0;
}

define和typedef

define是一个预处理指令,用于定义符号常量和宏,编译前,预处理器用定义的值替换调代码中的符号

#include <iostream>
#define PI 3.14159
#define SQUARE(x) ((x) * (x))int main() {std::cout << "Value of PI: " << PI << std::endl;std::cout << "Square of 5: " << SQUARE(5) << std::endl;return 0;
}

typedef:为现有的类型创建一个新名称

#include <iostream>typedef unsigned long ulong;
typedef int (*func_ptr)(int, int);int add(int a, int b) {return a + b;
}int main() {ulong myNumber = 1000;std::cout << "Value of myNumber: " << myNumber << std::endl;func_ptr fptr = add;std::cout << "Sum of 3 and 4: " << fptr(3, 4) << std::endl;return 0;
}

 两者比较

  • define:用于定义符号常量和宏,预处理阶段替换,代码可读性差
  • typedef:为类型创建别名,在编译阶段进行替换,代码可读性较好

class和struct

两者区别

  • 默认访问权限:class成员默认是私有的,struct成员默认是公有的
  • 使用场景:class通常用于定义复杂的数据结构和具有成员函数对象,struct则反之
//注意,struct也可以定义公有、私有、保护成员
struct ExampleStruct {int publicValue; // 公有成员private:int privateValue; // 私有成员protected:int protectedValue; // 保护成员
};

sizeof(1==1)在C和C++中结果分析

1==1在C和C++结果不同的原因

  • 本质上是一个比较操作符,判断两个整数是否相等,所以在C和C++中返回的是一个布尔值
  • C中的布尔值是用int类型表示,所以1==1则返回1
  • C++在C++98标准开始,有自己的专属bool类型,所以会返回true

sizeof(1==1)

  • C中sizeof(1==1) 等价于 sizeof(int),因为int类型大小是4字节,所以最终结果是4
  • C++中布尔类型占有1个字节,所以返回结果为1

memmove函数

memmove

  • C标准库的函数,用于在内存中移动数据,比memcpy更安全,因为它处理了重叠区域情况
  • 作用:将原地址所指向的某个内存区域中的数据复制到目标地址所指向的另一个内存区域中
  • 参数解释
    • dest:目标内存指针
    • src:源内存指针
    • n:复制字节数
  • 返回值:返回dest

原理简析

  • 内部检查源地址和目标地址是否重叠,如果重叠则会从src的末尾开始复制,以避免覆盖源数据 

 

#include <stdio.h>
#include <string.h>int main() {char str[] = "Hello, World!";printf("Original string: %s\n", str);// 使用 memmove 进行重叠内存区域的移动memmove(str + 7, str, 6); // 将 "Hello," 移动到 " World!" 之前printf("After memmove: %s\n", str);return 0;
}

auto

auto(自动类型推导,编译器根据初始化表达式的类型来推导变量类型)

#include <vector>
#include <iostream>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};// 使用 auto 来简化迭代器声明for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}return 0;
}

推导规则总结

  • 等式后是引用,则取出引用;如果auto后有&,则不去除
  • 顶层的const会被去除

new

new用于动态分配内存,为对象或者的数据类型分配相应的内存,并返回指向该内存的指针。new不仅分配内存,还调用构造函数来初始化对象

  • new和delete原理分析
    • new分配内存的时候,会调用操作系统的内存分配函数(一般情况下是malloc),然后返回指向分配内存的指针
    • new然后使用构造函数来初始化对象
    • delete释放内存的时候,调用对象的析构函数,然后调用操作系统内存释放函数
  • 注意
    • 内存泄漏:每次使用完new分配的内存后必须使用delete释放,否则会导致内存泄漏
    • 智能指针:尽量使用智能指针防止内存泄漏
    • new分配数组的时候,必须使用delete[ ] 释放内存
#include <iostream>class MyClass {
public:MyClass() {std::cout << "Constructor called!" << std::endl;}~MyClass() {std::cout << "Destructor called!" << std::endl;}
};int main() {MyClass* objArray = new MyClass[3]; // 分配 MyClass 类型的对象数组,调用构造函数delete[] objArray;                  // 释放内存,调用析构函数return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/388971.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

考研数学|保100冲130暑假强化保姆级规划

只做这些的话还不够&#xff0c;还要加上真题、模拟题。而且必须确保自己完全掌握上面的内容。 只看30讲和做1000题考90分是比较有困难的。如果刷完知能行1000题&#xff0c;90分应该很稳。 张宇1000题是考研数学难度较大一些的题集&#xff0c;题目难&#xff0c;计算量大&a…

机器学习笔记 - RAFT 光流简读

一、光流 光流是图像序列中像素的表观运动。为了估计光流,场景中物体的移动必须具有相应的亮度位移。这意味着一个图像中移动的红球在下一个图像中应该具有相同的亮度和颜色,这使我们能够确定它以像素为单位移动了多少。下图显示了光流示例,其中一系列图像捕获了逆时针旋转的…

增加一个按钮,批量获取凭证号

create PROCEDURE Cux_Ar_ServiceLedger_Voucher_ProcOrgId Int ,result Int output AS BEGIN SET NOCOUNT ONDECLARE Date DATETIME IF OrgId 0 or OrgIdBEGIN RAISERROR(N获取当前组织ID失败&#xff01;, 16, 1) RETURNEND SET Date GETDATE()BEGIN TRANSACTION BEGIN…

微调(一)

微调有两种办法&#xff0c; 一是模型全部参数的微调&#xff0c;二是少量参数高效的微调。前者由于参数多&#xff0c;需要的GPU多&#xff0c;并且全参数微调可能把模型带偏&#xff0c;后者只需要微调少量参数&#xff0c;需要的GPU少&#xff0c;还可能达到不错的效果&…

秒懂Linux之自动化构建工具-make/Makefile

目录 一.前文摘要 二.make/Makefile 一.前文摘要 在学习自动化构建工具前我们先来补充一下动静态库的相关指令 动态库指令 gcc -o 文件&#xff08;重命名&#xff09; 源文件 静态库指令 gcc -o 文件&#xff08;重命名&#xff09; 源文件 -static 二.make/Makefile 怎么形…

MATLAB(14)预处理

一、前言 在MATLAB中进行插值拟合、主成分分析&#xff08;PCA&#xff09;和小波分析之前&#xff0c;通常需要对数据进行一些预处理。这些预处理步骤可能包括数据清洗、缺失值处理、标准化或归一化等。下面我将分别为这三种分析方法提供预处理模型的示例代码。 二、实现 1.…

校园点餐系统

1 项目介绍 1.1 摘要 在这个被海量信息淹没的数字化时代&#xff0c;互联网技术以惊人的速度迭代&#xff0c;信息的触角无处不在&#xff0c;社会的脉动随之加速。每一天&#xff0c;我们都被汹涌而至的数据浪潮包裹&#xff0c;生活在一个全方位的数字信息矩阵中。互联网的…

大模型微调实战项目总结(非常详细)零基础入门到精通,收藏这一篇就够了

写在前面 不知不觉之间&#xff0c;距开源ChatGLM-Finetuning项目已经过去了8个月。大模型也在飞速的发展&#xff0c;开源社区也是越来越活跃&#xff0c;开源模型越来越多。 中间更新过一次&#xff0c;将代码重构让大家更容易理解&#xff0c;本次更新主要增加ChatGLM3模型…

JavaScript (十)——JavaScript 比较 和 逻辑运算符

目录 JavaScript 比较 和 逻辑运算符 比较运算符 如何使用 逻辑运算符 条件运算符 语法 JavaScript 比较 和 逻辑运算符 比较和逻辑运算符用于测试 true 或者 false 比较运算符 比较运算符在逻辑语句中使用&#xff0c;以测定变量或值是否相等。 如何使用 可以在条件语…

【C++】模拟实现list

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.了解项目及其功能 &#x1f4cc;了解list官方标准 了解模拟实现list &#x1f4cc;了解更底层的list实现 二.list迭代器和vector迭代器的异同 &#x1f4cc;迭代…

tomcat配置(java环境配置)

继昨天上线商城系统 [rootstaticserver eleme_web]# cd /usr/local/nginx/conf [rootstaticserver conf]# ls fastcgi.conf koi-utf nginx.conf scgi_params.default fastcgi.conf.default koi-win nginx.conf.bak uwsgi…

采用GDAL批量波段运算计算植被指数0基础教程

采用GDAL批量波段运算计算植被指数0基础教程 1. 引言 在传统的遥感数据处理方法中&#xff0c;通常使用ArcGis或ENVI软件进行波段运算。然而&#xff0c;这些软件在处理大量数据时往往效率低下。有没有一种方法可以批量进行波段运算&#xff0c;一下子计算几十个植被指数&…

计算word文件打印页数 VBA实现

目录 场景复现环境说明实现原理计算当前文件夹下所有word文件页数总和利用递归计算当前文件夹所有work文件页面数量几个BUG计算结果软件报价后话 场景复现 最近需要帮我弟打印高考资料&#xff0c;搜集完资料去网上打印&#xff0c;商家发出了这个计算页数的界面。我就好奇怎么…

如何把视频语音转文字?交给这4款工具就完事

这两天巴黎奥运会的盛大开幕&#xff0c;世界各地的记者们纷纷涌入这个体育盛事的现场&#xff0c;带着他们的镜头和麦克风&#xff0c;捕捉每一个激动人心的瞬间。 然而&#xff0c;随着采访的深入&#xff0c;如何快速准确地将这些珍贵的视频内容转化为文字记录&#xff0c;…

C语言 | Leetcode C语言题解之第309题买卖股票的最佳时机含冷冻期

题目&#xff1a; 题解&#xff1a; int maxProfit(int* prices, int pricesSize) {if (pricesSize 0) {return 0;}int f0 -prices[0];int f1 0;int f2 0;for (int i 1; i < pricesSize; i) {int newf0 fmax(f0, f2 - prices[i]);int newf1 f0 prices[i];int newf2…

Linux 和 Unix 的关系

Linux 和 Unix 的关系 2.2.1unix 是怎么来的 2.2.2Linux 是怎么来的 GNU计划的另一个目的是构建自由的软件文化&#xff0c;以支持以无条件自由软件和开放源码程序这种文化理念为核心的一整套系统&#xff0c;来推动软件在世界范围内的普及及发展。其中包括支持点&#xff08;推…

海思Hi35XX系列(一)环境搭建与挂载

小白一个&#xff0c;新的开发板刚到手有点懵&#xff0c;之前没弄过没有经验&#xff0c;简单记录一下吧 一般买开发板都会给带一个已经配置好的虚拟机文件&#xff0c;直接使用就可以 一、下载安装虚拟机与镜像文件 VMware-workstation16.1.0 我的镜像文件是官方文档资料…

路径规划——广度优先搜索与深度优先搜索

路径规划——广度优先搜索与深度优先搜索 https://www.hello-algo.com/chapter_graph/graph_traversal/ 1.广度优先搜索 Breath-First-Search 在图论中也称为广度优先遍历&#xff0c;类似于树的层序遍历。 算法原理 从起始节点出发&#xff0c;首先访问它的邻近节点&…

Typora2024最新版破解方法(亲测可用)

此方法非常简单&#xff0c;无需安装dll补丁&#xff0c;无需修改注册表&#xff0c;无需使用老版本。仅需修改部分文件内容即可 方法步骤 步骤一 下载并安装Typora 安装Typora 打开官网 下载并安装最新版即可 点击访问Typora官网 https://typoraio.cn/ 步骤二 修改文件 …

C#编写多导联扫描式的波形图Demo

本代码调用ZedGraph绘图框架&#xff0c;自己先安装好ZedGraph环境&#xff0c;然后拖一个zedGraphControl控件就行了&#xff0c;直接黏贴下面代码 基本代码显示 using System; using System.Windows.Forms; using ZedGraph; using System.Timers;namespace ECGPlot {public…