create my own memset function in c

北城余情 提交于 2020-01-03 03:06:07

问题


here is the prototype:

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

first im not sure if I have to return something because when I use the memset i do for example

memset(str, 'a', 5);

instead of

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

here is where I am with my code:

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);
}

I dont want to use array in this function, to better understand pointer and memory, so I dont get 2 things: - how to copy the int c into a character on my void b pointer - what condition to use on my while to be sure it stop before a '\0' char

edit: i was wondering is there a way to do this function without casting ?


回答1:


how to copy the int c into a character on my void b pointer

You convert the void pointer to an unsigned char pointer:

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);
}

what condition to use on my while to be sure it stop before a '\0' char

memset have to trust the length that is passed in. memset needs to work on a general piece of memory, not just a 0 terminated string - so there should not be such a check.

If you anyway would need to check for a 0 byte. you'd do

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



回答2:


Pointer arithmetic is based on offsetting the pointer by the size of the type it points to. Before you start incrementing that pointer, you should transform it from void* to pointer to 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;
}

also note that memset returns a pointer to the memory area s, so you should return the original pointer (before you start incrementing it).




回答3:


The reason functions often return a value is to return an error state to the calling function. In memory related functions it's usually the same pointer as where your result should be (including NULL). In your example you might not want to use the return value of your my_memset function, but usually it's because it can be included in a code evaluation (can't think of a better word for this), e.g.

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

or in a macro, e.g. to return pointer to the end of the memory where you copied your char:

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

This is probably not a great example (plus the potential issues if a is already a pointer, etc...), but it shows that you can reuse the result without having to write another couple of lines for this to evaluate the result and so on.

You should also check your pointers before dereferencing them. If for example void *b is NULL, you'll have a segmentation fault.

Nothing wrong with passing in void *, other than the fact that the intention of the function may not be as clear as when passing pointer to a particular data type. Make sure you cast it to something valid though inside. Also this way, the function can be used to set any memory to a particular hex value (through char) or all 0's quite easily.

It would seem like in this case b should be cast to the same type as the value you're trying to copy into it, an int; however, then the len argument becomes unclear, is it size in bytes or number of times c should be copied to the b pointer?

Since in your main() you're copying a char into that memory location, then it's just better to change your c to a char, cast your b to a char* and make len the length in bytes or number of times c should be copied to *b. Avoid ambiguity.

The way you have written it, it will copy c number of times specified by len or until you meet the null character, whichever is shortest/soonest. That's fine, if that's your intention.

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);
    }
}



回答4:


You could use a duff device to have even better performance.

#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)



回答5:


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);
}



回答6:


I tried one implementation like this:

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

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


来源:https://stackoverflow.com/questions/18851835/create-my-own-memset-function-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!