5

Given an index and an array of integers, I need to delete the element in the given array which was stored in the given index through the use of memcpy(). The new set of elements will be stored on the given array.

Here's an illustration of what I want to do, though I'm having trouble implementing it.

enter image description here

So arrayElem after deleting 10 would look like this:

enter image description here

Paul R
  • 208,748
  • 37
  • 389
  • 560
Kael
  • 391
  • 1
  • 10
  • 21

4 Answers4

7

You can't use memcpy, because source and destination overlap, but you can use memmove, e.g.:

memmove(&a[1], &a[2], 5 * sizeof(a[0]));

This copies the 5 elements starting at a[2] down to the 5 elements starting at a[1], taking care of the fact that the source and destination regions overlap.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • Sir, but how come my instructor said that it was possible? – Kael Jul 09 '15 at 14:24
  • 4
    Perhaps your instructor is not as smart as he thinks he is ? Refer him to the man pages for memcpy/memmove (linked above) if he doesn't believe you. – Paul R Jul 09 '15 at 14:25
  • 1
    @newbie well, if he had not imposed a restriction on using a temporary array, this is not impossible using `memcpy()`, IMHO. Check the below answer. – Sourav Ghosh Jul 09 '15 at 14:29
  • Sir Paul, how come when I tried using memmove with these values: 10 4 2 3 6 7 1 9 5 8. and deleted at index 1. The resulting values would be: 10 2 3 6 7 1 1 9 5 8. There's a repetition of a number which is 1. – Kael Jul 09 '15 at 14:55
  • @newbie See my answer.:) – Vlad from Moscow Jul 09 '15 at 14:57
  • 1
    @newbie: you only moved 5 elements - you would need to have moved 8 elements in this example. – Paul R Jul 09 '15 at 14:57
  • @Paul Sorry forgot to change it, but the values now also contains duplicates. Here's the current values: 10 2 3 6 7 1 9 5 8 8. Should I post my code? – Kael Jul 09 '15 at 15:08
  • 1
    @newbie: take some time to understand what `memmove` does, and also look at @Vlad's answer, as he explains why you get duplicate elements at the end of the array. Note that there is no such thing as an "empty" array element - there will always be some value in any unused element(s). – Paul R Jul 09 '15 at 15:09
  • I got it now and I know why there was a "duplicate". Thanks Sir Paul, Sir Sourav – Kael Jul 09 '15 at 15:18
2

You may not use function memcpy because the ranges of the array overlap each other. In this case the behaviour will be undefined.

Instead you have to use standard function memmove.

Here is a demonstrative program

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

size_t remove_by_index( int a[], size_t n, size_t i )
{
    if ( i < n )
    {
        memmove( a + i, a + i + 1, ( n - i - 1 ) * sizeof( *a ) );
        --n;
    }

    return n;
}

int main( void ) 
{
    int a[] = { 1, 10, 5, 8, 4, 51, 2 };
    const size_t N = sizeof( a ) / sizeof( *a );
    size_t n = N;

    for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
    printf( "\n" );

    n = remove_by_index( a, n, 1 );

    for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
    printf( "\n" );

    return 0;
}

The program output is

1 10 5 8 4 51 2 
1 5 8 4 51 2 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    The last element is always duplicated... I don't know how you got that output. – Mecanik Dec 12 '19 at 14:07
  • @NorbertBoros Do you see the assignment to n n = remove_by_index( a, n, 1 );? – Vlad from Moscow Dec 12 '19 at 14:36
  • Yep, I saw that. In my case that was not necessary. My problem was const size_t N = sizeof( a ) / sizeof( *a ), instead of doing this I was using my own "counter." See: https://stackoverflow.com/questions/59291982/deleting-element-and-resizing-fixed-size-array-of-structures I am able to remove an element and shift them back with your solution, many thanks :) – Mecanik Dec 12 '19 at 14:41
1

You caanot do this using memcpy() on the same array. You need to use memmove().

To quote the memcpy() man page

The memcpy() function copies n bytes from memory area src to memory area dest. The memory areas must not overlap. Use memmove(3) if the memory areas do overlap.

Ref: memmove()

However, if you use a temporary array, then, in 2-steps, you can achieve this using memcpy(), like

  • memcpy() the required part of your given array to the temporary array
  • memcpy() back the temporary array to the given array starting from the required index.

FWIW, neither of the above approach will clear the value in index 6. The existing value will be present. You need to do that manually.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

If you "must" use memcpy, then you can copy 1 byte at a time right on down the array to prevent source and destination overlapping. In this case, memcpy is standing in for a single memory assignment and is extremely inefficient, but it will do what you want.

for(int i=1; i<=5; i++)
{
    memcpy(arrayElem[i], arrayElem[i+1], sizeof(*arrayElem));
}

Icky, but follows the letter of the law laid down in the assignment. memmove though is 100% the correct way to actually do this without the requirement.

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61