好吧,我想要一个像memsetbut for 这样的函数struct,以便它可以在某些或所有元素上使用,如下所示:

// create array of person data elements
struct {
  unsigned char name[25];
  unsigned char age;
  unsigned int numberPhone;
} persons [256];

// the 256 people have the same name
memset(person, { "Mohammed", 0, 0 } ,sizeof(persons) / sizeof(persons[0]));

我可以使用for loop,但我更喜欢使用memset,因为在这种情况下它的性能更好for loop

9

  • 3
    为何要使用memset


    – 

  • 1
    memset 不是那样工作的。它也不是那些不能轻易复制的类/结构的定义行为。(虽然你帖子中的结构是。)


    – 

  • 1
    除此之外:unsigned int numberPhone;完全不行。请使用字符串,例如char numberPhone[16];


    – 


  • 2
    使用 for 循环,memset 不适用于此要求。您不能仅凭愿望就能获得更高性能的代码。


    – 

  • 4
    C 还是 C++?您已标记两者。


    – 


最佳答案
3

您不能用于此。将内存区域中的std::memset所有字节设置为相同的值:

void* memset( void* dest, int ch, std::size_t count );

将值复制static_cast<unsigned char>(ch)到 指向的对象的前 count 个字符中dest

如果所有 256 个对象都应使用相同的值进行初始化,则只需将其设置为默认值:

struct {
    unsigned char name[25] = "Mohammed";
    unsigned char age = 0;
    unsigned int numberPhone = 0;
} persons [256];

不再需要其他东西了。

如果您想要默认值,请创建一个实例,然后创建一个数组:

#include <algorithm>    // fill
#include <iostream>
#include <iterator>     // begin, end
#include <type_traits>  // remove_reference

int main() {
    struct {
        unsigned char name[25];
        unsigned char age;
        unsigned int numberPhone;
    } persons[256];

    // an instance with the proper values:
    std::remove_reference_t<decltype(persons[0])> temp{
        .name = "Mohammed", .age = 0, .numberPhone = 0};

    // fill the array
    std::fill(std::begin(persons), std::end(persons), temp);
}

注意:std::remove_reference_t<decltype(persons[0])>这是获取匿名类类型的一种繁琐方法。最好为您创建的类型命名。

memset不适合初始化结构,因为它只能将每个字节设置为相同的值。对于像您这样的具有不同数据类型的结构,您需要定义一个默认结构,并使用为此目的设计的循环或标准函数将其复制到数组中的每个元素,这可以保持良好的性能和正确性。

标准 C 函数memset声明如下

void *memset(void *s, int c, size_t n);

也就是说,它会用存储在第二个参数中的单个字符填充第一个参数指向的所有内存。因此,它不适合完成像你这样的任务。

另外,最好使用命名结构,因为这将简化对结构类型的引用。并且至少数据成员age应该具有类型unsigned int而不是类型,char因为否则,无论如何age您都需要将其转换为类型(例如int或)才能输出unsigned int

memset如果你确实指的是 C++,那么你可以使用标准算法来代替使用std::for_each。例如

这是一个演示程序。

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    const std::size_t numberOfPersons = 5 /*or 264*/;
    struct Person
    {
        unsigned char name[25];
        unsigned int age;
        unsigned int numberPhone;
    } persons[numberOfPersons];

    std::for_each( std::begin( persons ), std::end( persons ),
        []( auto &person )
        {
            person = { "Mohammed", 0, 0 };
        } );

    for ( const auto &person : persons )
    {
        const auto &[name, age, numberPhone] = person;
        std::cout << "name = " << name 
            << ", age = " << age 
            << ", phone number = " << numberPhone << '\n';
    }
}

程序输出是

name = Mohammed, age = 0, phone number = 0
name = Mohammed, age = 0, phone number = 0
name = Mohammed, age = 0, phone number = 0
name = Mohammed, age = 0, phone number = 0
name = Mohammed, age = 0, phone number = 0

std::for_each或者,您可以使用标准算法std::generate 或标准算法代替标准算法,std::fill如下所示

std::generate( std::begin( persons ), std::end( persons ),
    []() -> Person
    {
        return { "Mohammed", 0, 0 };
    } );

或者

std::fill( std::begin( persons ), std::end( persons ),
     Person { "Mohammed", 0, 0 } );

或者如果你还不知道标准算法,那么就使用基于范围的 for 循环,例如

for (auto &person : persons)
{
    person = { "Mohammed", 0, 0 };
}

但最简单的方法是在声明中初始化结构,无需任何算法或使用默认初始化程序的循环。

#include <iostream>

int main()
{
    const std::size_t numberOfPersons = 5 /*or 264*/;
    struct Person
    {
        unsigned char name[25] = "Mohammed";
        unsigned int age = 0;
        unsigned int numberPhone = 0;
    } persons[numberOfPersons];

    for ( const auto &person : persons )
    {
        const auto &[name, age, numberPhone] = person;
        std::cout << "name = " << name 
            << ", age = " << age 
            << ", phone number = " << numberPhone << '\n';
    }
}

正如您所看到的,没有使用 memset,也没有使用任何算法,甚至也没有使用循环来初始化数组。:)

考虑到这个基于范围的 for 循环

for ( const auto &person : persons )
{
    const auto &[name, age, numberPhone] = person;
    std::cout << "name = " << name 
        << ", age = " << age 
        << ", phone number = " << numberPhone << '\n';
}

可以改写为

    for (const auto &[name, age, numberPhone] : persons)
    {
        std::cout << "name = " << name
            << ", age = " << age
            << ", phone number = " << numberPhone << '\n';
    }
}

这些循环仅从 C++17 标准开始有效。否则你可以写

for ( const auto &person : persons )
{
    std::cout << "name = " << person.name 
        << ", age = " << person.age 
        << ", phone number = " << person.numberPhone << '\n';
}

对于 C 来说,除了使用循环之外没有其他方法,因为在 C 中您可能无法为数据成员声明具有默认初始化程序的结构。

如果您已经初始化了结构数组的一个元素,那么要为所有其他元素复制初始化程序,您可以再次使用标准算法,std::fill例如

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    const std::size_t numberOfPersons = 5 /*or 264*/;
    struct Person
    {
        unsigned char name[25];
        unsigned int age;
        unsigned int numberPhone;
    } persons[numberOfPersons] = { "Mohammed", 0, 0 };

    std::fill( std::next( std::begin( persons ) ), std::end( persons ), persons[0] );

    for (const auto &[name, age, numberPhone] : persons)
    {
        std::cout << "name = " << name
            << ", age = " << age
            << ", phone number = " << numberPhone << '\n';
    }
}

可以在 C 中使用相同的方法

#include <stdio.h>

int main(void) 
{
    enum { numberOfPersons = 5 /*or 264*/ };
    
    struct Person
    {
        unsigned char name[25];
        unsigned int age;
        unsigned int numberPhone;
    } persons[numberOfPersons] = { [0] = { .name = "Mohammed", .age = 0, .numberPhone = 0 } };
        
    for ( size_t i = 1; i < numberOfPersons; i++ )
    {
        persons[i] = persons[0];
    }
        
    for ( size_t i = 0; i < numberOfPersons; i++ )
    {
        printf( "name = %s, age = %u, phone number = %u\n", 
            persons[i].name, persons[i].age, persons[i].numberPhone );
    }
}