setfill, fill 和 memset 的用法

std::fill 的语法与功能

std::fill 是 C++ 标准库中的一个函数,用于快速填充容器或数组的某个范围的元素为指定值。它被定义在头文件 <algorithm> 中。


语法
std::fill(first, last, value);
  • first

    • 填充范围的起始迭代器或指针。
    • 指向需要填充的第一个元素。
  • last

    • 填充范围的结束迭代器或指针。
    • 不包含在填充范围内(即左闭右开区间 [first, last))。
  • value

    • 用于填充的值。

功能

std::fill 会将从 firstlast 的所有元素(包括起点但不包括终点)设置为 value


示例

1. 填充数组
#include <iostream>
#include <algorithm>

int main() {
    int arr[10];
    
    // 使用 std::fill 将数组的所有元素设置为 42
    std::fill(arr, arr + 10, 42);

    // 输出数组内容
    for (int i = 0; i < 10; i++) {
        std::cout << arr[i] << " ";
    }
    return 0;
}

输出

42 42 42 42 42 42 42 42 42 42

解释

  • arr 是一个长度为 10 的整数数组。
  • std::fill(arr, arr + 10, 42) 会将数组从 arr[0]arr[9] 的所有元素都设置为 42

2. 填充容器
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec(5); // 创建一个大小为 5 的 vector

    // 使用 std::fill 将所有元素设置为 99
    std::fill(vec.begin(), vec.end(), 99);

    // 输出 vector 内容
    for (int num : vec) {
        std::cout << num << " ";
    }
    return 0;
}

输出

99 99 99 99 99

解释

  • vec 是一个大小为 5 的 std::vector
  • std::fill(vec.begin(), vec.end(), 99) 会将 vec 的所有元素都设置为 99

3. 填充部分范围
#include <iostream>
#include <algorithm>

int main() {
    int arr[10];

    // 将数组的前 5 个元素设置为 1
    std::fill(arr, arr + 5, 1);

    // 将数组的后 5 个元素设置为 0
    std::fill(arr + 5, arr + 10, 0);

    // 输出数组内容
    for (int i = 0; i < 10; i++) {
        std::cout << arr[i] << " ";
    }
    return 0;
}

输出

1 1 1 1 1 0 0 0 0 0

解释

  • std::fill(arr, arr + 5, 1) 将数组的前 5 个元素设置为 1
  • std::fill(arr + 5, arr + 10, 0) 将数组的后 5 个元素设置为 0

代码中 std::fill 的用法

在你提供的代码中,std::fill 被用来初始化动态分配的数组:

std::fill(ret.digits, ret.digits + ret.size, 0);
解释
  • ret.digits
    • 动态分配的整数数组,表示结果大整数的每一位。
  • ret.digits + ret.size
    • 数组的末尾指针,表示需要填充的范围不包括 ret.digits + ret.size
  • 0
    • 填充值,将数组中所有元素都设置为 0

为什么使用 std::fillmemset 更好?

你原本的代码使用了 memset 来初始化数组:

memset(ret.digits, 0, sizeof(int) * ret.size);
问题分析
  • memset 的局限性

    • memset 是一个 C 风格的函数,用于将指定的字节填充到内存中。
    • 它只支持按字节填充,而数组的元素是 int 类型(通常是 4 字节或其他长度)。
    • 如果内存布局不匹配(如不同大小的 int 类型),可能导致未定义行为。
  • std::fill 的优势

    • std::fill 是 C++ 的标准库函数,能够安全地填充任意类型的数组或容器。
    • 它会根据数组元素的类型大小,逐个填充正确的值。

总结

  1. 语法

    std::fill(first, last, value);
    
    • 填充范围 [first, last) 内的所有元素为 value
  2. 用法

    • 可用于初始化数组或容器中的元素。
    • memset 更安全,更灵活。
  3. 代码中的作用

    • 在动态数组 ret.digits 中,将所有元素初始化为 0
  4. 推荐

    • 在现代 C++ 中,优先使用 std::fill 代替 memset,尤其是在处理非字节数据时。

memset 的详细语法知识

memset 是 C 标准库中的一个函数,用于快速初始化一段内存。它可以将某个值填充到指定的内存区域,通常用于清零或设置某种固定值。


1. memset 的函数原型

void* memset(void* ptr, int value, size_t num);
参数说明
  1. ptr:

    • 指向需要初始化的内存区域的起始地址
    • 是一个 void* 类型指针,可以用于任何数据类型的内存块。
  2. value:

    • 要填充的值,按字节填充
    • 实际上是一个整数,但只取低 8 位(即一个字节)的值。
  3. num:

    • 要填充的字节数。
    • 这个参数指定了从 ptr 开始的连续字节数会被填充为 value
返回值
  • 返回指向 ptr 的指针(即填充的内存起始地址)。

2. 作用

  • 按字节将一段内存区域设置为指定的值。
  • 常用于初始化动态分配的内存、数组或结构体等。

3. memset 的使用语法和示例

示例 1:清零一个数组
#include <iostream>
#include <cstring>  // 包含 memset
using namespace std;

int main() {
    int arr[10];  // 定义一个整数数组

    // 使用 memset 将整个数组清零
    memset(arr, 0, sizeof(arr));

    // 输出数组内容
    for (int i = 0; i < 10; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

输出

0 0 0 0 0 0 0 0 0 0

解释

  1. sizeof(arr)
    • 计算整个数组的大小(字节数)。对于 int arr[10],假设 int 是 4 字节,则数组大小是 4 * 10 = 40 字节。
  2. memset(arr, 0, sizeof(arr))
    • 从数组的起始地址 arr 开始,将接下来的 40 个字节设置为 0x00
  3. 整数数组被清零
    • 每个整数占 4 个字节,全 0 的二进制表示对应的整数值是 0

示例 2:设置特定值
#include <iostream>
#include <cstring>
using namespace std;

int main() {
    char buffer[10];

    // 使用 memset 将 buffer 中所有字节设置为 'A'
    memset(buffer, 'A', sizeof(buffer));

    // 输出结果
    for (int i = 0; i < 10; i++) {
        cout << buffer[i] << " ";
    }
    cout << endl;

    return 0;
}

输出

A A A A A A A A A A

解释

  1. sizeof(buffer)
    • 返回 buffer 数组的大小(10 字节)。
  2. memset(buffer, 'A', sizeof(buffer))
    • buffer 的每个字节都设置为 'A'(ASCII 值为 65,即 0x41)。
  3. 注意
    • 填充的值 'A' 是按字节写入的。

示例 3:初始化结构体
#include <iostream>
#include <cstring>
using namespace std;

struct Person {
    char name[20];
    int age;
    float height;
};

int main() {
    Person p;

    // 使用 memset 将整个结构体清零
    memset(&p, 0, sizeof(p));

    // 输出结果
    cout << "Name: " << p.name << endl;
    cout << "Age: " << p.age << endl;
    cout << "Height: " << p.height << endl;

    return 0;
}

输出

Name: 
Age: 0
Height: 0

解释

  1. sizeof(p)
    • 返回结构体 p 的总大小(字节数)。
  2. memset(&p, 0, sizeof(p))
    • 将结构体 p 的所有成员都设置为 0
      • name 数组的每个字节被设置为 '\0'
      • ageheight 的二进制全 0 表示值为 0

示例 4:错误用法
#include <iostream>
#include <cstring>
using namespace std;

int main() {
    int arr[10];

    // 错误:将数组中的每个字节设置为 1
    memset(arr, 1, sizeof(arr));

    // 输出结果
    for (int i = 0; i < 10; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

输出(可能的结果):

16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009

解释

  1. 问题
    • memset(arr, 1, sizeof(arr)) 将数组的每个字节设置为 0x01
    • arr 是一个 int 数组,假设 int 占用 4 字节,每个整数的内存被填充为 0x01010101(即 16843009)。
  2. 结论
    • memset 不适合用于非零初始化整数数组,因为它是逐字节填充的。

4. memset 的常见用法

用法 1:清零
  • 最常见的用途是将数组、结构体或内存块清零。
memset(arr, 0, sizeof(arr)); // 清零数组
用法 2:填充特定值
  • 也可以用于填充特定的单字节值(如 'A'255)。
memset(buffer, 'A', sizeof(buffer)); // 填充字符 'A'
用法 3:初始化结构体
  • 可将结构体中的所有成员初始化为 0。
memset(&structVar, 0, sizeof(structVar));

5. memset 的优点和局限性

优点
  1. 快速

    • memset 是用 C 编写的底层函数,执行速度非常快。
    • 通常会通过硬件指令优化(如 REP STOSB 指令)。
  2. 简单

    • 用法简单,特别适合清零内存块。
  3. 通用

    • 可以用于初始化任何类型的内存块。
局限性
  1. 逐字节操作

    • memset 按字节填充,对多字节类型(如 intfloat)可能产生意外结果。
    • 比如,将 int 数组中的每个字节填充为 1 并不等于将每个整数赋值为 1
  2. 不调用构造函数/析构函数

    • 如果用于类对象或复杂类型,memset 不会调用构造函数和析构函数,可能导致未定义行为。
  3. 仅适用于简单初始化

    • 如果需要更复杂的初始化逻辑(如逐元素初始化为不同的值),memset 不适用。

6. 替代方案

在现代 C++ 中,可以使用更安全、更高效的方式代替 memset

使用 std::fill
  • 用于填充容器或数组的范围:
std::fill(arr, arr + 10, 1); // 将数组的所有元素设置为 1
使用构造函数初始化
  • 对于类或复杂类型,使用构造函数进行初始化:
std::vector<int> vec(10, 0); // 创建大小为 10 的 vector,每个元素初始化为 0

总结

  • memset 的功能
    • 按字节初始化内存区域,常用于清零或设置固定值。
  • 用法
    • 最适合用于清零简单类型的数组或结构体。
  • 注意事项
    • 按字节填充,可能对多字节类型产生非预期结果。
    • 不会调用复杂类型的构造函数或析构函数。

setfillstd::fill 的区别

  • setfill
    • 是一个 I/O 操作工具,用于设置填充字符,通常与 std::setw 搭配,用于格式化输出时对固定宽度的空白部分填充指定字符。
    • 定义在头文件 <iomanip> 中。
  • std::fill
    • 是一个 算法工具,用于填充容器或数组的某个范围中的元素为指定值。
    • 定义在头文件 <algorithm> 中。

1. setfill 的用法

作用

setfill 设置输出时用来填充指定宽度的空白字符。配合 std::setw 一起使用时,可以指定一个固定宽度,当输出的内容不足该宽度时,用填充字符补齐。

语法
std::setfill(character);
  • 参数
    • character:用于填充空白的字符。
示例 1:基础用法
#include <iostream>
#include <iomanip> // for std::setfill and std::setw
using namespace std;

int main() {
    cout << std::setfill('*') << std::setw(5) << 42 << endl;
    cout << std::setfill('#') << std::setw(7) << 123 << endl;
    return 0;
}

输出

***42
####123

解释

  • std::setw(5) 表示输出宽度为 5。
  • std::setfill('*') 设置填充字符为 '*',所以输出不足 5 位的部分用 '*' 补齐。
  • 类似地,std::setfill('#') 会用 '#' 补齐宽度不足的部分。

示例 2:填充字符串和浮点数
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    cout << std::setfill('0') << std::setw(8) << "C++" << endl;
    cout << std::setfill('.') << std::setw(10) << 3.14 << endl;
    return 0;
}

输出

00000C++
.......3.14

解释

  • "C++"3.14 的输出宽度不足时,分别用 '0''.' 补齐。

注意点
  1. 只影响下一个输出

    • setfillsetw 只对接下来的输出生效一次。
    cout << std::setfill('*') << std::setw(5) << 42 << 99 << endl;
    

    输出为:

    ***4299
    
    • 解释:setw(5) 只对 42 生效,99 直接紧跟其后输出,没有影响。
  2. 需要搭配 setw

    • 如果不使用 setwsetfill 是无效的,因为它只影响宽度不足的情况。

2. std::fill 的用法

作用

std::fill 是 C++ 标准库中的算法函数,用于填充数组或容器的某个范围内的元素为指定值。

语法
std::fill(first, last, value);
  • 参数
    • first:填充范围的起始迭代器或指针。
    • last:填充范围的结束迭代器或指针(不包括 last 指向的元素)。
    • value:用于填充的值。
示例 1:填充数组
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int arr[10];
    std::fill(arr, arr + 10, 42); // 将数组的所有元素填充为 42

    for (int i = 0; i < 10; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

输出

42 42 42 42 42 42 42 42 42 42

解释

  • std::fill(arr, arr + 10, 42) 会从 arr[0]arr[9] 填充为 42

示例 2:填充 std::vector
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> vec(5); // 创建一个大小为 5 的 vector

    std::fill(vec.begin(), vec.end(), 99); // 填充 vector 的所有元素为 99

    for (int num : vec) {
        cout << num << " ";
    }
    return 0;
}

输出

99 99 99 99 99

解释

  • std::fill(vec.begin(), vec.end(), 99)vec 中的所有元素填充为 99

示例 3:填充部分范围
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int arr[10];
    std::fill(arr, arr + 5, 1);  // 填充前 5 个元素为 1
    std::fill(arr + 5, arr + 10, 0); // 填充后 5 个元素为 0

    for (int i = 0; i < 10; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

输出

1 1 1 1 1 0 0 0 0 0

解释

  • 前 5 个元素(arr[0]arr[4])被填充为 1
  • 后 5 个元素(arr[5]arr[9])被填充为 0

两者的区别

特性setfillstd::fill
定义用于格式化输出,设置宽度不足时的填充字符。用于填充容器或数组的元素为指定值。
头文件<iomanip><algorithm>
操作对象输出流(如 std::cout)。数组或容器的某个范围。
使用场景配合 setw,用于控制输出格式。用于批量初始化或填充元素。
适用类型输出字符(字节)。所有支持赋值操作的类型(基本或复杂类型)。
是否类型安全是的,适用于字符填充。是的,适用于任意类型的填充。
典型用途输出格式控制(如补零或对齐)。数组/容器初始化或重置值。

总结

  • setfill

    • 是一个 I/O 操作工具,主要用于格式化输出。通常配合 setw 使用,用指定的字符填充宽度不足的部分。
    • 用法:std::setfill('*') << std::setw(5) << 42;
  • std::fill

    • 是一个算法工具,主要用于填充容器或数组中的元素为指定值。
    • 用法:std::fill(arr, arr + 10, 42);

两者用途完全不同,setfill 针对输出流,std::fill 针对容器/数组填充。根据场景选择合适的工具!如果还有问题,欢迎继续提问!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值