Mimicking memmove's behaviour

185 Views Asked by At

I am attempting to create a function with a similar work to memmove. I found in the man that the copying is done by including a transitionnal array to where bytes are copied first , which should not overlap with dest, then copied to destination. This the code I attempted to make (including the necessary headers):

void    *ft_memmove(void *dest, const void *src, size_t n)
{
    unsigned char p[n];
    unsigned char *p2;
    const unsigned char *p3;
    size_t i;

    p2 = dest;
    p3 = src;
    i = 0;
    while (i < n)
        *(p + i++) = *(p3++);
    while (n--)
        *(p2++) = *(p++);
    return (dest);
}

I believe the problem is related to assigning the const void array's elements to p while it is a constant or something similar. Should I use malloc or is there another possible way? Or my uderstanding of how memmove actually wroks is wrong because I found other definitions somewhere else.

I ran the previous code on this main:

int main()
{
    char s1[] = "holala";
    char s2[] = "dongo";

    ft_memmove(s1, s2, sizeof(s2));
    printf("%p,\n", s1);
}

It should've shown "donga", instead I get this error:

ft_memmove.c:17:22: error: lvalue required as increment operand
   17 |         *(p2++) = *(p++);
2

There are 2 best solutions below

10
Barmar On BEST ANSWER

p is an array, not a pointer, so you can't increment it. Use different variables for the temporary array and the pointer, so you can increment the pointer.

void    *ft_memmove(void *dest, const void *src, size_t n)
{
    unsigned char temp[n];
    unsigned char *p = temp;
    unsigned char *p2;
    const unsigned char *p3;

    p2 = dest;
    p3 = src;
    for (sizt_t i = 0; i < n; i++) {
        *(p++) = *(p3++);
    }
    p = temp;
    while (n--) {
        *(p2++) = *(p++);
    }
    return (dest);
}

Or you could do it like the way you assigned to p in the first loop, using *(p2++) = *(p + i++)

1
nielsen On

It is possible to mimic memmove() without a temporary array, but it is not straightforward and there is a lesson to be learned from that, so let us have a try.

With memmove(), the source(S) and destination(D) areas may overlap. There are 4 possibilities:

  1. S and D are completely disjoint
  2. S and D are identical
  3. D overlaps the lower part of S
  4. D overlaps the higher part of S

If bytes are copied one by one from the beginning of S, then the only problematic case is "4", where bytes have to be copied in reverse order:

void *ft_memmove(void *dest, const void *src, size_t n)
{
    unsigned char * D = dest;
    const unsigned char * S = src;
    if(is_within_and_not_equal(D, S, n))
    { // Reverse order
        D += n-1;
        S += n-1;
        for(size_t i = 0; i < n; i++)
        {
            *(D--) = *(S--);
        }
    }
    else
    {
        for(size_t i = 0; i < n; i++)
        {
            *(D++) = *(S++);
        }
    }
    return dest;
}

It may be chosen to extend this by identifying cases "1" (use memcpy) and "2" (do nothing).

Notice the helper function is_within_and_not_equal(D, S, n). This must check if D is within the array S of n elements, i.e. if D > S && D < S + n. However, the result of that comparison is unspecified by the standard unless D points into the same area as S. Therefore, a portable implementation would need to be:

    #include<stdbool.h>

    bool is_within_and_not_equal(const unsigned char *D, const unsigned char *S, size_t n)
    {
        for(size_t i = 1; i < n; i++)
        {
            if(D == S+i) return true;
        }
        return false;
    }

A major point in having the standard library functions is that, behind the scene, they may be implemented in a non-portable way taking advantage of additional prerequisites than those specified in the C Standard.

No sane standard library implementation would use something like the above implementation of is_within_and_not_equal(), but when we try to implement standard library functions using only the standard language assumptions, it may not be possible to implement these functions efficiently or implement them at all.