c++学习笔记(8)

1.

C++中的strlen函数用于计算字符串的长度,直到遇到空字符('0')为止,但不包括这个空字符本身。

strlen是C语言标准库中的一个函数,它的作用是确定一个以空字符结尾的字符数组(即C风格字符串)的长度。这个函数在头文件中定义,通常在需要知道字符串长度时使用,例如在复制或比较字符串时。

关键点:

  1. 函数原型:size_t strlen(const char *str),其中size_t是一个无符号整数类型,用于表示对象的大小。

  2. 参数:str是一个指向字符的指针,该字符是待测量长度的字符串的第一个字符。

  3. 返回值:函数返回的是字符串的实际长度,即从第一个字符开始到第一个空字符('\0')之间的字符数。

  4. 注意事项:strlen函数不计算空字符本身的长度,这是因为C风格字符串以空字符作为字符串的结束标志。如果传递给strlen的指针没有指向有效的以空字符结尾的字符串,那么函数的行为是未定义的,可能会导致程序崩溃或者返回错误的长度值。

  5. 与sizeof的区别:strlen计算的是字符串内容的实际长度,而sizeof运算符计算的是数据类型或数据结构的大小,包括任何填充或空白字符。

  6. 使用场景:strlen常用于需要知道字符串长度的情况,如分配内存、字符串处理等。

  7. 安全使用:在使用strlen之前,应确保字符串是以空字符结尾的,以避免潜在的安全问题。

// 首先定义了一个名为my_string的字符串常量。
// 然后,使用strlen()函数获取该字符串的长度,并将结果存储在length变量中。
// 最后,使用std::cout将字符串长度输出到控制台。
// 需要注意的是,strlen()函数返回的是size_t类型的值,而不是整数类型。
// 这是因为字符串的长度可能超过整数类型的范围。
// 此外,strlen()函数只能用于以null结尾的字符数组,不能用于其他类型的数据结构。

#include 
#include 

int main() {
    // 定义一个字符串
    const char* my_string = "Hello, world!";

    // 使用strlen()函数获取字符串的长度
    size_t length = strlen(my_string);

    // 输出字符串长度
    std::cout << "Length of the string is: " << length << std::endl;
    return 0;
}

2.

在C++中,bitset是一个标准库模板类,用于处理固定大小的位序列(即一组二进制数字)。bitset可以高效地存储和操作位级别的数据。

基本概念:

  • 声明和初始化:

    • 你可以定义一个具有特定位数的bitset对象,例如bitset<32>定义了一个32位的bitset对象。

    • bitset对象可以用二进制字符串进行初始化,例如bitset<8> b("10101010")。

  • 成员函数:

    • size():返回bitset对象的位数。

    • count():返回bitset对象中值为1的位数。

    • test(pos):测试位于pos位置的位是否为1,返回布尔值。

    • set(pos, val):设置位于pos位置的位为val指定的值(0或1)。

    • reset(pos):将位于pos位置的位重置为0。

    • flip(pos):翻转位于pos位置的位(0变为1,1变为0)。

    • to_ulong():将bitset对象转换为无符号长整型(如果bitset大小超过无符号长整型的位数,则行为未定义)。

  • 运算符:

    • 赋值运算符:可以对bitset对象使用=运算符进行赋值。

    • 索引运算符:可以使用[]访问或修改bitset中的特定位。

    • 逻辑运算符:可以对bitset对象使用&(与)、|(或)、^(异或)等位运算符。

  • 用途:

    • bitset通常用于需要位级操作的场景,如位掩码、位字段操作、位压缩存储等。

 示例:

#include 
#include 

int main() {
    std::bitset<8> bs1; // 定义一个8位的bitset对象

    bs1 = std::bitset<8>("11001010"); // 用二进制字符串初始化
    std::cout << "bs1: " << bs1 << std::endl; // 输出:bs1: 11001010

    std::bitset<8> bs2(54); // 用十进制数初始化,54的二进制表示是110110
    std::cout << "bs2: " << bs2 << std::endl; // 输出:bs2: 110110

    std::bitset<8> bs3;
    bs3.set(3, 1); // 将第4位(从右到左,从0开始计数)设置为1
    bs3.reset(0); // 将第1位设置为0
    std::cout << "bs3: " << bs3 << std::endl; // 输出:bs3: 11101000

    bool is_set = bs3.test(3); // 检查第4位是否为1
    std::cout << "Is bit 3 set? " << (is_set ? "Yes" : "No") << std::endl; // 输出:Is bit 3 set? Yes
    return 0;
}

由于bitset的大小是在编译时确定的,因此它不适合处理动态大小的位序列。对于这种情况,可以考虑使用std::vector或其他容器类型。

   

3.

在C++中,count()函数用于计算某个特定元素在给定范围内的出现次数。这个函数通常用于标准库容器如vector和string,也可用于数组。count()函数的一些基本信息:

  • 函数原型: int count (const T& val, const vector& vec); 对于string类型,函数原型为: int count (char c, const string& str);

  • 参数说明:

    • 第一个参数是要计数的元素值。

    • 第二个参数是搜索的范围,即容器的起始迭代器和结束迭代器(对于数组而言,则是数组的首地址和尾地址加一)。

  • 返回值:

    • 返回指定元素在给定范围内出现的次数。

  • 使用示例:

  • 对于vector:
vector vec = {1, 2, 3, 1, 4, 1};
int total = count(1, vec); // 返回1在vec中出现的次数
  • 对于string:
string mainString = "Let life be beautiful like summer flowers, death like autumn leaves";
int total = count('l', mainString); // 返回字符'l'在mainString中出现的次数
  • 注意事项:
  • count()函数在使用时需要注意包含正确的头文件,对于vector,需要包含头文件;对于string,则需要包含头文件。

4.

C++中的std::any是一个类型安全的容器,可以存储任意类型的数据。

std::any是在C++17标准中引入的,它提供了一种灵活的方式来存储和管理不同类型的值。

主要特点:

  1. 类型安全:与void*指针不同,std::any类型提供了类型安全保证。它可以存储任何类型的值,包括基本类型(如int、double、char、float等)和复合类型(如类、结构体等)。

  2. 值存储:std::any不仅能够存储值,还能够检查是否存储了值,并且可以安全地检索和转换存储的值。

  3. 异常安全性:尝试将错误的类型赋值给std::any对象或从中提取值时,会抛出std::bad_any_cast异常,这有助于避免类型错误导致的运行时问题。

  4. 使用方式:使用std::any时,通常需要包含头文件,并使用std::any的make_any函数来创建std::any实例,使用type()成员函数来获取存储的类型,以及any_cast来进行类型转换和值的提取。

std::any是C++17中引入的一个非常有用的特性,它为处理未知类型或需要在运行时动态改变类型的场景提供了强大的支持。

// 首先创建了一个名为my_any的空的any对象。
// 然后,将一个整数和一个字符串分别赋值给my_any。
// 接下来,使用type()函数检查my_any是否包含一个特定类型的值,并使用any_cast()函数将其转换为相应的类型。
// 最后,输出了my_any中的整数值和字符串值。
// 需要注意的是,在使用any时,必须确保所存储的值的类型与实际使用的类型匹配,否则可能会导致未定义的行为。
// 此外,any不支持默认构造函数,因此必须在创建时立即初始化。

#include 
#include 

int main() {
    // 创建一个空的any对象
    std::any my_any;

    // 将整数赋值给my_any
    my_any = 42;

    // 检查my_any是否包含一个整数
    if (my_any.type() == typeid(int)) {
        // 将my_any转换为整数并输出
        std::cout << "Integer value: " << std::any_cast(my_any) << std::endl;
    }

    // 将字符串赋值给my_any
    my_any = std::string("Hello, world!");

    // 检查my_any是否包含一个字符串
    if (my_any.type() == typeid(std::string)) {
        // 将my_any转换为字符串并输出
        std::cout << "String value: " << std::any_cast(my_any) << std::endl;
    }
    return 0;
}

5.

在C++中,nullptr是一个关键字,代表空指针常量。

nullptr是在C++11标准中引入的,用来更明确地表示空指针的概念。与旧式的NULL或null(通常被定义为0或者(void*)0)不同,nullptr具有类型安全的特性,它不会隐式转换为整数类型,这避免了一些潜在的错误和混淆。

以下是nullptr的一些主要特点:

  • 类型安全:nullptr的类型是std::nullptr_t,它是一个无法被隐式转换为任何其他类型的特殊类型。

  • 通用性:nullptr可以用于任何类型的指针,包括函数指针、成员指针等。

  • 清晰性:使用nullptr可以使代码更加清晰和易于理解,因为它清楚地表达了“无指针”的意图。

  • 兼容性:虽然nullptr是C++11引入的,但许多编译器在C++11之前就已经支持了类似的概念。

6.

在C++中,set是一个标准库容器,用于存储唯一元素的集合。

主要特点:

  1. 自动排序:set中的元素会根据其值自动排序,且所有元素都是唯一的,即不允许有重复的元素存在。

  2. 插入和删除:向set中插入或删除元素通常是对数时间复杂度的操作,这是因为set通常实现为红黑树或其他自平衡的二叉搜索树。

  3. 支持迭代器:可以使用迭代器遍历set中的所有元素。

  4. 支持集合操作:如并集、交集、差集等。

  5. 初始化方式:可以默认初始化一个空的set,也可以用其他set对象的元素来初始化,或者通过迭代器的开始和结束位置来初始化。

set在C++中是一个功能强大的容器,特别适用于需要快速检索、插入和删除唯一元素的场景。

// 示例:首先创建了一个空的set容器my_set,然后使用insert函数向其中插入了三个整数。
// 接着,使用迭代器遍历my_set中的所有元素并输出。
// 最后,使用erase函数删除了值为2的元素,并再次遍历my_set中的所有元素并输出。

#include 
#include 

int main() {
    // 创建一个空的set容器
    std::set my_set;

    // 向set中插入元素
    my_set.insert(1);
    my_set.insert(2);
    my_set.insert(3);

    // 遍历set中的元素并输出
    for (auto it = my_set.begin(); it != my_set.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 删除set中的某个元素
    my_set.erase(2);

    // 再次遍历set中的元素并输出
    for (auto it = my_set.begin(); it != my_set.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    return 0;
}

7.

在C++中,reset()函数通常与智能指针一起使用,用于改变智能指针的指向或者释放其当前所指向的对象。

智能指针是C++中一种自动管理内存的对象,它可以确保在不再需要时自动释放所指向的对象。std::shared_ptr和std::unique_ptr等智能指针类型都提供了reset()成员函数,这个函数有两种常见的用法:

  • 释放当前对象:当调用reset()而不提供参数时,智能指针会释放其所指向的对象。如果该对象是通过new分配的,那么它将被删除。

  • 更改指向:当reset()接收一个指针作为参数时,智能指针会释放当前对象,并开始指向新的内存地址。新对象的生命周期将由智能指针管理。

此外,reset()函数也常用于微控制器或其他系统级编程中,在这些情况下,它可能涉及到硬件的重置操作,这与智能指针的概念不同。

它有助于避免内存泄漏和其他与内存管理相关的问题。在使用reset()时,应确保理解其行为和对程序状态的影响,特别是在涉及共享所有权或资源时。

// 首先创建了一个名为my_ptr的智能指针,并将其指向一个新分配的整数对象。
// 然后,使用reset()函数释放了该对象,并将my_ptr设置为空指针。
// 最后,检查my_ptr是否为空,以验证reset()函数的行为。
#include 
#include 

int main() {
    // 创建一个智能指针并指向一个整数对象
    std::shared_ptr my_ptr = std::make_shared(42);

    // 输出当前指针所指向的值
    std::cout << "Current value: " << *my_ptr << std::endl;

    // 使用reset()释放当前对象
    my_ptr.reset();

    // 再次输出当前指针所指向的值(此时应该为空)
    std::cout << "After reset: " << (my_ptr ? "not null" : "null") << std::endl;
    return 0;
}

8.

在C++中,flip()通常用于指代图像处理中的翻转操作。

OpenCV库中的flip()函数能够对二维矩阵(例如图像)进行垂直或水平翻转。这个函数接受三个参数:输入图像、输出图像和翻转代码。根据传入的翻转代码(flipCode),flip()函数可以执行以下操作:

  • 垂直翻转:当flipCode等于0时,图像会沿着垂直轴翻转。这意味着图像的顶部与底部互换,左侧与右侧不变。这种翻转方式在某些视频处理操作中很常见。

  • 水平翻转:当flipCode大于0时,图像会沿着水平轴翻转。在这种模式下,图像的左侧与右侧互换,而顶部和底部保持不变。这种水平镜像在某些对称性检查中可能会用到。

  • 同时垂直和水平翻转:当flipCode小于0时,图像会同时沿垂直和水平轴翻转。这相当于将图像旋转180度,中心的每个像素点映射到其对应的四象限位置。

// 首先使用OpenCV库中的imread()函数读取一张名为example.jpg的图像。
// 然后,使用flip()函数将该图像进行水平翻转,并将结果存储在另一个Mat对象中。
// 最后,使用imshow()函数显示原始图像和翻转后的图像,并使用waitKey()函数等待用户按下任意键后关闭窗口。
#include 
#include 

int main() {
    // 读取一张图像
    cv::Mat image = cv::imread("example.jpg");

    // 检查图像是否成功加载
    if (image.empty()) {
        std::cout << "Failed to load image" << std::endl;
        return -1;
    }

    // 创建一个用于存储翻转结果的Mat对象
    cv::Mat flipped_image;

    // 水平翻转图像
    cv::flip(image, flipped_image, 1);

    // 显示原始图像和翻转后的图像
    cv::imshow("Original Image", image);
    cv::imshow("Flipped Image", flipped_image);

    // 等待用户按下任意键后关闭窗口
    cv::waitKey(0);
    return 0;
}

你可能感兴趣的:(c++,学习,笔记)