重新分配后如何将新内存清零

发布于 2024-08-19 09:40:35 字数 1321 浏览 3 评论 0原文

调用 realloc 后将新内存清零同时保持最初分配的内存完整的最佳方法是什么?

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

size_t COLORCOUNT = 4;

typedef struct rgb_t {
    int r;
    int g;
    int b;
} rgb_t;

rgb_t** colors;

void addColor(size_t i, int r, int g, int b) {
    rgb_t* color;
    if (i >= COLORCOUNT) {
        // new memory wont be NULL
        colors = realloc(colors, sizeof(rgb_t*) * i);
       //something messy like this...
        //memset(colors[COLORCOUNT-1],0 ,sizeof(rgb_t*) * (i - COLORCOUNT - 1));

         // ...or just do this (EDIT)
        for (j=COLORCOUNT; j<i; j++) {
            colors[j] = NULL;
        }

        COLORCOUNT = i;
    }

    color = malloc(sizeof(rgb_t));
    color->r = r;
    color->g = g;
    color->b = b;

    colors[i] = color;
}

void freeColors() {
    size_t i;
    for (i=0; i<COLORCOUNT; i++) {
        printf("%x\n", colors[i]);
        // can't do this if memory isn't NULL
       // if (colors[i])
         //   free(colors[i]);

    }
}


int main() {
    colors = malloc(sizeof(rgb_t*) * COLORCOUNT);
    memset(colors,0,sizeof(rgb_t*) * COLORCOUNT);
    addColor(0, 255, 0, 0);
    addColor(3, 255, 255, 0);
    addColor(7, 0, 255, 0);


    freeColors();
    getchar();
}

What is the best way to zero out new memory after calling realloc while keeping the initially allocated memory intact?

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

size_t COLORCOUNT = 4;

typedef struct rgb_t {
    int r;
    int g;
    int b;
} rgb_t;

rgb_t** colors;

void addColor(size_t i, int r, int g, int b) {
    rgb_t* color;
    if (i >= COLORCOUNT) {
        // new memory wont be NULL
        colors = realloc(colors, sizeof(rgb_t*) * i);
       //something messy like this...
        //memset(colors[COLORCOUNT-1],0 ,sizeof(rgb_t*) * (i - COLORCOUNT - 1));

         // ...or just do this (EDIT)
        for (j=COLORCOUNT; j<i; j++) {
            colors[j] = NULL;
        }

        COLORCOUNT = i;
    }

    color = malloc(sizeof(rgb_t));
    color->r = r;
    color->g = g;
    color->b = b;

    colors[i] = color;
}

void freeColors() {
    size_t i;
    for (i=0; i<COLORCOUNT; i++) {
        printf("%x\n", colors[i]);
        // can't do this if memory isn't NULL
       // if (colors[i])
         //   free(colors[i]);

    }
}


int main() {
    colors = malloc(sizeof(rgb_t*) * COLORCOUNT);
    memset(colors,0,sizeof(rgb_t*) * COLORCOUNT);
    addColor(0, 255, 0, 0);
    addColor(3, 255, 255, 0);
    addColor(7, 0, 255, 0);


    freeColors();
    getchar();
}

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

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

发布评论

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

评论(5

柳絮泡泡 2024-08-26 09:40:35

没有办法将这个问题作为一般模式来解决。原因是为了知道缓冲区的哪一部分是新的,您需要知道旧缓冲区有多长。在 C 中不可能确定这一点,因此无法找到通用解决方案。

不过你可以像这样写一个包装器

void* realloc_zero(void* pBuffer, size_t oldSize, size_t newSize) {
  void* pNew = realloc(pBuffer, newSize);
  if ( newSize > oldSize && pNew ) {
    size_t diff = newSize - oldSize;
    void* pStart = ((char*)pNew) + oldSize;
    memset(pStart, 0, diff);
  }
  return pNew;
}

There is no way to solve this as a general pattern. The reason why is that in order to know what part of the buffer is new you need to know how long the old buffer was. It's not possible to determine this in C and hence prevents a general solution.

However you could write a wrapper like so

void* realloc_zero(void* pBuffer, size_t oldSize, size_t newSize) {
  void* pNew = realloc(pBuffer, newSize);
  if ( newSize > oldSize && pNew ) {
    size_t diff = newSize - oldSize;
    void* pStart = ((char*)pNew) + oldSize;
    memset(pStart, 0, diff);
  }
  return pNew;
}
别忘他 2024-08-26 09:40:35

可能不需要执行memset:在使用稍后有效的内容进行设置之前,您可能不会使用colors[k]。例如,您的代码将 colors[i] 设置为新分配的 color 指针,因此您不需要设置 colors[i]NULL

但是,即使您想“将其清零,这样一切都很好”,或者确实需要新指针为 NULL:C 标准并不保证所有位为零都是 null指针常量(即 NULL),因此 memset() 无论如何都不是正确的解决方案。

您可以做的唯一可移植的事情是在循环中将每个指针设置为 NULL:

size_t k;
for (k=COLORCOUNT; k < i+1; ++k) /* see below for why i+1 */
    colors[k] = NULL;

您的主要问题是您的 realloc() 调用是错误的。 realloc() 返回一个指向已调整大小的内存的指针,它不会(必然)就地调整其大小。

因此,您应该这样做:

/* i+1 because you later assign to colors[i] */
rgb_t **tmp = realloc(colors, (i+1) * sizeof *tmp);
if (tmp != NULL) {
    /* realloc succeeded, can't use colors anymore */
    colors = tmp;
} else {
    /* realloc failed, colors is still valid */
}

如果您确实想知道 memset() 调用应该是什么,则需要将从 colors+COLORCOUNT 开始的内存设置为零,并且将 i+1-COLORCOUNT 成员设置为零:

memset(colors+COLORCOUNT, 0, (i+1-COLORCOUNT) * sizeof *colors);

但正如我上面所说,所有字节为零并不能保证都是 NULL 指针,因此您的 memset() 无论如何都是没用的。如果您想要 NULL 指针,则必须使用循环。

There is probably no need to do the memset: you may not be using colors[k] before setting it with something valid later. For example, your code sets colors[i] to a newly allocated color pointer, so you didn't need to set colors[i] to NULL.

But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be NULL: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e., NULL), so memset() isn't the right solution anyway.

The only portable thing you can do is to set each pointer to NULL in a loop:

size_t k;
for (k=COLORCOUNT; k < i+1; ++k) /* see below for why i+1 */
    colors[k] = NULL;

Your primary problem is that your realloc() call is wrong. realloc() returns a pointer to the resized memory, it doesn't (necessarily) resize it in-place.

So, you should do:

/* i+1 because you later assign to colors[i] */
rgb_t **tmp = realloc(colors, (i+1) * sizeof *tmp);
if (tmp != NULL) {
    /* realloc succeeded, can't use colors anymore */
    colors = tmp;
} else {
    /* realloc failed, colors is still valid */
}

If you really want to know what the memset() call should be, you need to set to zero the memory starting at colors+COLORCOUNT, and set i+1-COLORCOUNT members to zero:

memset(colors+COLORCOUNT, 0, (i+1-COLORCOUNT) * sizeof *colors);

But as I said above, all bytes zero is not guaranteed to be a NULL pointer, so your memset() is useless anyway. You have to use a loop if you want NULL pointers.

不…忘初心 2024-08-26 09:40:35

首先,realloc 可能会失败,因此您需要检查 NULL。其次,没有更好的方法将内存清零:只需从旧缓冲区的末尾到较大缓冲区的末尾进行 memset 即可。

First of all, realloc can fail, so you need to check for NULL. Second, there is no better way to zero out the memory: just memset from the end of the old buffer to the end of the larger buffer.

简单 2024-08-26 09:40:35

编写您自己的函数,例如 reallocz,它接受当前大小作为参数,并为您调用 reallocmemset。它真的不会比你已经拥有的更好......毕竟它是 C。

Write your own function, say reallocz, that accepts the current size as a parameter, and calls realloc and memset for you. It really won't get much better than what you already have... it's C, after all.

离不开的别离 2024-08-26 09:40:35

在 Linux 上,现在有 size_t malloc_usable_size (void *ptr),由 提供。可以在 https://linux.die.net/man/3/malloc_usable_size。

这意味着您现在可以为 realloc(3) 编写通用包装器:

void *realloc_zero(void *oldptr, size_t reqsize) {
  size_t oldsize = malloc_usable_size(ptr);
  void *newptr;
  if ((newptr = realloc(ptr, reqsize)) == NULL) {
    return NULL;
  }
  size_t newsize = malloc_usable_size(newptr);
  if (oldsize < newsize) {
    memset((char *) newptr + oldsize, 0, newsize - oldsize);
  }
  return newptr;
}

请注意,malloc_usable_pointer(3) 不一定返回与您调用 calloc(3) 时使用的字节数相同 - 例如,

void *p = calloc(8, 1);
printf("%zu\n", malloc_usable_pointer(p));

在我的 Linux 计算机上打印 16
另请注意,您应该仅在通过 calloc(3) 获得的堆分配上调用上述 realloc_zero(),因为 calloc() 将对malloc_usable_pointer()报告的任何额外字节进行零初始化。

On Linux, there is now size_t malloc_usable_size (void *ptr), provided by <malloc.h>. Find the man page at https://linux.die.net/man/3/malloc_usable_size.

This means you now can write a general-purpose wrapper for realloc(3):

void *realloc_zero(void *oldptr, size_t reqsize) {
  size_t oldsize = malloc_usable_size(ptr);
  void *newptr;
  if ((newptr = realloc(ptr, reqsize)) == NULL) {
    return NULL;
  }
  size_t newsize = malloc_usable_size(newptr);
  if (oldsize < newsize) {
    memset((char *) newptr + oldsize, 0, newsize - oldsize);
  }
  return newptr;
}

Note that malloc_usable_pointer(3) doesn't necessarily return the same number of bytes that you called calloc(3) with -- for example,

void *p = calloc(8, 1);
printf("%zu\n", malloc_usable_pointer(p));

prints 16 on my Linux machine.
Also note that you should only call the above realloc_zero() on heap allocations obtained through calloc(3), since calloc() will zero-initialize any extra bytes reported by malloc_usable_pointer().

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