在c中创建我自己的memset函数

时间:2013-09-17 13:52:26

标签: c pointers memory memset pointer-arithmetic

这是原型:

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

首先我不确定我是否必须返回一些内容,因为当我使用memset时,例如

memset(str, 'a', 5);

而不是

str = memset(str, 'a', 5);

这是我的代码所在:

void *my_memset(void *b, int c, int len)
{
    int i;

    i = 0;
    while(b && len > 0)
    {
        b = c;
        b++;
        len--;
    }
    return(b);
}

int main()
{
    char *str;

    str = strdup("hello");
    my_memset(str, 'a', 5);
    printf("%s\n", str);
}

我不想在这个函数中使用数组,以便更好地理解指针和内存,所以我没有得到两件事: - 如何将int c复制到我的void b指针上的字符中 - 在我的时间使用什么条件,以确保它在'\ 0'字符

之前停止

编辑:我想知道有没有方法可以在没有强制转换的情况下执行此功能?

6 个答案:

答案 0 :(得分:6)

  

如何将int c复制到我的void b指针上的字符

将void指针转换为unsigned char指针:

void  *my_memset(void *b, int c, int len)
{
  int           i;
  unsigned char *p = b;
  i = 0;
  while(len > 0)
    {
      *p = c;
      p++;
      len--;
    }
  return(b);
}
  

我可以使用什么条件来确保它在'\ 0'char

之前停止
memset必须信任传入的长度.memset需要处理一般的内存,而不仅仅是一个0终止的字符串 - 所以不应该进行这样的检查。

如果你反正需要检查一个0字节。你会做的

if (*p == 0) //or if(!*p )
     break;

答案 1 :(得分:1)

指针算法基于将指针偏移其指向的类型的大小。在开始递增指针之前,您应该将其从void*转换为指向char / unsigned char的指针:

void* my_memset(void *s, int c, size_t len) {
    unsigned char *dst = s;
    while (len > 0) {
        *dst = (unsigned char) c;
        dst++;
        len--;
    }
    return s;
}

还要注意memset 返回指向内存区域的指针,因此您应该返回原始指针(在开始递增之前)。

答案 2 :(得分:1)

函数经常返回值的原因是将错误状态返回给调用函数。在与内存相关的函数中,它通常与结果应该是相同的指针(包括NULL)。在您的示例中,您可能不想使用my_memset函数的返回值,但通常是因为它可以包含在代码评估中(不能想到更好的单词),例如

if(!my_memset((void *)str, 'a', 5))
{
    printf("An error occurred in my_memset()\n");
}

或在宏中,例如返回指向您复制char的内存末尾的指针:

#define INIT_MEM_PTR_END(a,x) (my_memset((void *)&(a), (x), sizeof(a)) + sizeof(a))

这可能不是一个很好的例子(加上潜在的问题,如果a已经是一个指针等等),但它表明你可以重用结果而不必另外写几行这是为了评估结果等等。

在解除引用之前,您还应该检查指针。例如,如果void *b为NULL,则会出现分段错误。

传递void *没有错,除了函数的意图可能不像传递指针到特定数据类型时那样清晰。确保你把它投射到内部有效的东西。同样,这个函数可以用来将任何内存设置为特定的十六进制值(通过char)或非常容易的全部0。

在这种情况下,似乎应该将b转换为与您尝试复制到其中的值相同的类型int;但是,len参数变得不清楚,是以字节大小还是应将c复制到b指针的次数?

由于在main()中您将char复制到该内存位置,因此最好将c更改为char,投射您的b 1}}到char*并使len以字节或次数c的长度复制到*b。避免含糊不清。

您编写它的方式,它将复制c len指定的次数,或直到您遇到空字符,以最短/最快的为准。如果这是你的意图,那很好。

void *my_memset(void *b, char c, int len)
{
    char *b_char = (char *)b;

    if (b == NULL) return NULL;

    while(*b_char && len > 0)
    {
        *b_char = c;
        b_char++;
        len--;
    }

    return b; //as this pointer has not changed
}

int main()
{
    char *str;

    str = strdup("hello");
    if (!my_memset((void *)str, 'a', 5))
    {
        printf("An error occurred in my_memset()\n");
    }
    else
    {
        printf("%s\n", str);
    }
}

答案 3 :(得分:1)

您可以使用duff设备获得更好的性能。

#define DUFF_DEVICE_8(aCount, aAction) \
do { \
int count_ = (aCount); \
int times_ = (count_ + 7) >> 3; \
switch (count_ & 7){ \
case 0: do { aAction; \
case 7: aAction; \
case 6: aAction; \
case 5: aAction; \
case 4: aAction; \
case 3: aAction; \
case 2: aAction; \
case 1: aAction; \
} while (--times_ > 0); \
} \
} while (0)

答案 4 :(得分:0)

void   *my_memset(void *b, int c, int len)
{
  if (b == NULL || len <= 0)
      return b;
  unsigned char *ptr = b;
   while(*ptr != '\0' && len--)
    {
      *ptr++ = (unsigned char)c;
    }
  return(b);
}

答案 5 :(得分:0)

我试过这样一个实现:

    void memset(void *b, int c, int len)
    {
       char *s = b;

        while(len--)
            *s++ = c;
    }