使用memcpy在数组中进行删除

5
给定一个索引和一个整数数组,我需要使用memcpy()删除给定数组中存储在给定索引处的元素。新的一组元素将存储在给定数组中。
这是我想要做的事情的说明,但我在实现它时遇到了麻烦。
因此,在删除10后,arrayElem看起来像这样:

3
使用memmove函数。它是memcpy函数的“安全”版本,允许处理重叠的内存区域。 - Eugene Sh.
4个回答

7

如果源地址和目标地址重叠,你不能使用 memcpy,但可以使用 memmove 代替,例如:

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

这会将从a[2]开始的5个元素复制到从a[1]开始的5个元素,注意源区域和目标区域重叠的情况。

先生,但是我的导师怎么说这是有可能的呢? - Kael
4
也许你的教练没有他自认为的聪明?如果他不相信你的话,可以引用上面链接的memcpy/memmove的手册给他看。 - Paul R
1
@newbie 嗯,如果他没有限制使用临时数组,我认为使用 memcpy() 是不难实现的。请查看下面的答案。 - Sourav Ghosh
1
@新手:你只移动了5个元素 - 在这个例子中,你需要移动8个元素。 - Paul R
1
@新手:花点时间了解一下memmove的作用,并查看@Vlad的答案,因为他解释了为什么在数组末尾会出现重复元素。请注意,不存在“空”数组元素-任何未使用的元素中都将始终存在某些值。 - Paul R
显示剩余4条评论

2

如果数组的范围重叠,您可能无法使用函数 memcpy。在这种情况下,行为将是未定义的。

相反,您必须使用标准函数 memmove

这是一个演示程序:

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

程序输出为:
1 10 5 8 4 51 2 
1 5 8 4 51 2 

1
最后一个元素总是重复的...我不知道你是怎么得到那个输出的。 - Mecanik
@NorbertBoros 你看到对 n 的赋值 n = remove_by_index( a, n, 1 ); 吗? - Vlad from Moscow
是的,我看到了。在我的情况下,这并不是必要的。我的问题是const size_t N = sizeof(a) / sizeof(*a),而不是使用自己的“计数器”。请参见:https://stackoverflow.com/questions/59291982/deleting-element-and-resizing-fixed-size-array-of-structures 我能够使用您的解决方案删除元素并将其向后移动,非常感谢 :) - Mecanik

1
如果您“必须”使用memcpy,那么您可以逐个复制字节直到数组结束,以防止源和目标重叠。在这种情况下,memcpy代替了单个内存分配,并且极其低效,但它会实现您想要的功能。
for(int i=1; i<=5; i++)
{
    memcpy(arrayElem[i], arrayElem[i+1], sizeof(*arrayElem));
}

虽然有点不好看,但是这个做法符合任务中规定的法律要求。然而,使用memmove是百分之百正确的方法,而且没有这个要求也可以这样做。


1
您不能使用 memcpy() 在同一数组上进行操作,需要使用 memmove()。引用 memcpy() man page 的话来说:

memcpy() 函数将 n 个字节从内存区域 src 复制到内存区域 dest。内存区域不得重叠。如果内存区域重叠,请使用 memmove(3)

参考:memmove() 但是,如果您使用临时数组,则可以通过 2 步使用 memcpy() 实现此目的,如下所示:
  • memcpy() 您给定的数组的所需部分到临时数组
  • 从所需索引开始,将临时数组的内容回复到给定数组中,使用 memcpy()

值得一提的是,以上两种方法都无法“清除”索引为6的值。现有的值仍将存在。您需要手动完成此操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接