在C++中如何用类似memset的方式初始化结构体数组?
兄弟,我懂你想找个像memset那样高效的方法批量初始化结构体数组的心情,但先得给你泼个冷水:memset其实干不了这个活儿。
为啥呢?因为memset的核心逻辑是把一块内存的每个字节都设置成同一个值(比如全0或者0xFF),但你要的是给每个结构体元素设置成{"Mohammed", 0, 0}——这里面name是一串不同字节组成的字符串,age和numberPhone虽然是0,但整体没法用单一字节值填充出来。硬用memset的话,最多只能把整个数组填成全0,那name就变成空字符串了,完全不是你想要的效果。
不过别担心,C里有不少高效的替代方案,性能不会比memset差,还更符合C的写法:
方案1:用std::fill批量复制模板对象
这是最推荐的方法,编译器会把它优化成和memset类似的批量内存复制,效率拉满:
首先定义好结构体,然后创建一个“模板”结构体对象,把它初始化到你想要的状态:
#include <algorithm> // 包含std::fill的头文件 #include <cstring> // 包含strncpy的头文件 struct Person { unsigned char name[25]; unsigned char age; unsigned int numberPhone; }; // 创建初始化好的模板对象 Person default_person{}; // 用strncpy给name赋值,比strcpy更安全,避免字符串溢出 strncpy(reinterpret_cast<char*>(default_person.name), "Mohammed", sizeof(default_person.name) - 1); default_person.name[sizeof(default_person.name) - 1] = '\0'; // 确保字符串以'\0'结尾 default_person.age = 0; default_person.numberPhone = 0; // 定义结构体数组 Person persons[256]; // 用std::fill批量填充数组 std::fill(std::begin(persons), std::end(persons), default_person);
std::fill会把default_person的内容批量复制到数组的每个元素里,编译器优化后,这个操作的效率和memset几乎没有区别,而且代码更清晰、更安全。
方案2:数组定义时直接聚合初始化(适合小容量数组)
如果你的数组元素数量不多(比如不是256个),可以直接在定义数组的时候用聚合初始化:
Person persons[5] = { {"Mohammed", 0, 0}, {"Mohammed", 0, 0}, {"Mohammed", 0, 0}, {"Mohammed", 0, 0}, {"Mohammed", 0, 0} };
但像你这种256个元素的数组,写这么多行显然不现实,所以还是方案1更实用。
关于性能的补充
你担心手动写for loop性能不如memset?其实不用太焦虑——现在的编译器优化能力很强,只要你写的for loop逻辑简单(比如只是复制结构体),编译器会自动把它优化成批量内存复制,效率和memset、std::fill几乎一样。不过std::fill代码更简洁,也不容易写错,所以还是优先选它。
备注:内容来源于stack exchange,提问作者M 027

