以通用方式安全地初始化 C 中的数组

发布于 2024-11-27 23:28:50 字数 565 浏览 1 评论 0原文

我编写了一些代码,使用 memset 来初始化内置类型的数组,例如整数、短整型、浮点型,更重要的是指针,就像

typedef void* slot_t;
#define EMPTY_SLOT (slot_t)NULL
...
int n = 10;
slot_t slots[] = (slot_t[])malloc(sizeof(slot_t)*n)
memset(slots,(int)EMPTY_SLOT,n*sizeof(slot_t));

这段代码在 Linux32 中运行良好 一样memset 接受 32 位 int 作为第二个参数(即初始化元素),但对于 Linux64 来说并非如此,其中sizeof(slot_t)>sizeof(int),以及 IIRC,在其他平台中,memset 接受 char 作为其第二个参数。我尚未验证我在项目中遇到的任何错误是否是由于此造成的,但无论如何,可以肯定的是,最好采用更安全但仍然“通用”的方法(如果存在)。你知道吗?

I wrote some code that uses memset to initialize arrays of built-in types like ints, shorts, floats and, more importantly, pointers, like

typedef void* slot_t;
#define EMPTY_SLOT (slot_t)NULL
...
int n = 10;
slot_t slots[] = (slot_t[])malloc(sizeof(slot_t)*n)
memset(slots,(int)EMPTY_SLOT,n*sizeof(slot_t));

this code works nicely in Linux32 where memset accepts 32-bit ints as second argument (i.e. initializing element), but it's not so for Linux64, where sizeof(slot_t)>sizeof(int), and, IIRC, in other platforms where memset accepts char as its second argument. I have yet to verify that any of the bugs I'm experiencing in my project is due to this but, anyway, to be sure, it would be better to adopt a safer, but still "generic", method, if exists. Do you know any?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你的心境我的脸 2024-12-04 23:28:50

使用它的干净内存

slot_t slots[] = (slot_t[])calloc(n,sizeof(slot_t))

单独

Use

slot_t slots[] = (slot_t[])calloc(n,sizeof(slot_t))

it's clean memory by itself

尴尬癌患者 2024-12-04 23:28:50

memset 用字节填充内存。请参阅此处

如果您想要一个通用解决方案 - 您应该编写一个可以迭代和填充的循环。如果你用 0 填充,那么它是什么类型的数据以及它的大小并不重要 - 只需用整个数组的 siezof 填充 0 (sizeof(slot_t) *n)。由于您使用的是 NULL,它不必为 0(尽管通常是) - 我建议采用更安全的“循环”方法。

memset fills memory with bytes. See here.

If you want a generic solution - you should write a loop that would iterate and fill. If you're filling with 0, then it doesn't matter what type of data it is and what size it has - just fill 0 with siezof of the whole array (sizeof(slot_t)*n). Since you're using NULL, which doesn't have to be 0 (although usually is) - I suggest taking the safer "loop" approach.

往日 2024-12-04 23:28:50

memset 实际上需要一个字符作为填充内存的值——请注意,它按字节填充。所以只需说0。如果需要,您可以将其放入 EMPTY_SLOT 宏中。或者,使用calloc()

(此外,malloc() 调用的返回类型应为 slot_t *。)

memset really wants a character as the value to fill the memory with -- note that it fills bytewise. So just say 0. You can put that in your EMPTY_SLOT macro if you want. Alternatively, use calloc().

(Also, the return type of your malloc() call should be slot_t *.)

烟燃烟灭 2024-12-04 23:28:50

memset() 的第二个参数是 int 类型,但它指定要存储在目标的每个字节中的值 - 这意味着,如果 sizeof(int) == 4,您将应有的内存归零四倍。

slots 数组进行零填充的方法是

memset(slots, 0, n * sizeof *slots);

(假设 slots 被正确声明为指针而不是数组),但空指针表示不是保证全位为零(可能是,但您不应该依赖它)。

如果您想要完全的可移植性,则需要编写一个循环将每个元素设置为 NULL。

如果您愿意假设空指针全位为零,则可以使用 memset - 但请务必按​​照我指定的方式调用它。

The second argument to memset() is of type int, but it specifies a value to be stored in each byte of the destination -- which means that, if sizeof(int) == 4, you're zeroing four times as much memory as you should be.

The way to zero-fill the slots array would be

memset(slots, 0, n * sizeof *slots);

(assuming slots is correctly declared as a pointer rather than as an array), except that a null pointer representation isn't guaranteed to be all-bits-zero (it probably is, but you shouldn't depend on it).

If you want complete portability, you'll need to write a loop to set each element to NULL.

If you're willing to assume that null pointers are all-bits-zero, you can use memset -- but be sure to call it as I specified.

虐人心 2024-12-04 23:28:50

如果您想要一个完全通用的函数,它将对象数组设置为某个“模板”对象指定的值,您可以使用如下函数:

void init_array( void* arr, size_t nmemb, size_t size, void const* initializer)
{
    size_t i = 0;

    char* p = (char *) arr;

    for (i = 0; i < nmemb; ++i) {
        memcpy( p, initializer, size);
        p += size;
    }
}

那么您的分配/初始化代码可能如下所示:

typedef void* slot_t;

static const slot_t empty_slot = NULL;    // or make this a global if that 
                                          //  works better for your scenario

int n = 10;

// note: your original `malloc()` line:
//
//      slot_t slots[] = (slot_t[])malloc(sizeof(slot_t)*n)
//
// wouldn't work, as you can't assign to an array as a whole.
// That line shouldn't even compile.

slot_t* slots = (slot_t*)malloc(sizeof(slot_t)*n);

// completely generic initialization
init_array( slots, n, sizeof(slot_t), &empty_slot);

如果您想初始化一个指针数组,您可以使用另一个函数来更直接地处理这种情况:

void init_ptr_array( void* arr, size_t nmemb, void* initializer)
{
    size_t i = 0;
    void* p;

    for (; p < arr + nmemb; ++p) {
        *p = initializer;
    }
}

// arrays of object pointers
init_ptr_array( slots, n, empty_slot);

我不确定我是否喜欢这两个函数对最后一个参数有细微不同的含义。如果我的程序需要这两种初始化,我可能也会坚持使用通用初始化指针数组。它的效率可能会低一些,但初始化通常不是瓶颈。

If you want a completely generic function that will set an array of objects to the values specified by some 'template' object, you could use a function like the following:

void init_array( void* arr, size_t nmemb, size_t size, void const* initializer)
{
    size_t i = 0;

    char* p = (char *) arr;

    for (i = 0; i < nmemb; ++i) {
        memcpy( p, initializer, size);
        p += size;
    }
}

Then your allocation/initialization code might look like:

typedef void* slot_t;

static const slot_t empty_slot = NULL;    // or make this a global if that 
                                          //  works better for your scenario

int n = 10;

// note: your original `malloc()` line:
//
//      slot_t slots[] = (slot_t[])malloc(sizeof(slot_t)*n)
//
// wouldn't work, as you can't assign to an array as a whole.
// That line shouldn't even compile.

slot_t* slots = (slot_t*)malloc(sizeof(slot_t)*n);

// completely generic initialization
init_array( slots, n, sizeof(slot_t), &empty_slot);

If you want to initialize an array of pointers, you could have another function that handled that case a little more directly:

void init_ptr_array( void* arr, size_t nmemb, void* initializer)
{
    size_t i = 0;
    void* p;

    for (; p < arr + nmemb; ++p) {
        *p = initializer;
    }
}

// arrays of object pointers
init_ptr_array( slots, n, empty_slot);

I'm not sure I like that the two functions have a subtly different meaning for last parameter. If I had a need for both kinds of initialization in my program, I'd probably stick with using the generic one for initializing pointer arrays as well. It might be a bit less efficient, but initialization isn't usually a bottleneck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文