【问题标题】:Remove element from dynamic array of structure从结构的动态数组中删除元素
【发布时间】:2018-06-29 15:03:43
【问题描述】:

我在 C 工作

我有一个名为 Entity 的结构,并创建了该结构的动态数组。然后我尝试从数组中删除一个元素,但我没有得到我想要的行为。

这是我正在使用的代码:

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

typedef struct Entity
{
    int x, y;
    int velX, velY;
}Entity;

int remove_element(Entity** array, int sizeOfArray, int indexToRemove)
{
    int i;

    printf("Beginning processing. Array is currently: ");
    for (i = 0; i < sizeOfArray; ++i)
        printf("%d ", (*array)[i].x);
    printf("\n");

    Entity* temp = malloc((sizeOfArray - 1) * sizeof(Entity)); // allocate an array with a size 1 less than the current one

    memmove(
            temp,
            *array,
            (indexToRemove+1)*sizeof(Entity)); // copy everything BEFORE the index

    memmove(
            temp+indexToRemove,
            (*array)+(indexToRemove+1),
            (sizeOfArray - indexToRemove)*sizeof(Entity)); // copy everything AFTER the index


    printf("Processing done. Array is currently: ");
    for (i = 0; i < sizeOfArray - 1; ++i)
        printf("%d ", (temp)[i].x);
    printf("\n");

    free (*array);
    *array = temp;
    return 0;

}

int main()
{
    int i;
    int howMany = 20;

    Entity* test = malloc(howMany * sizeof(Entity*));

    for (i = 0; i < howMany; ++i)
        (test[i].x) = i;

    remove_element(&test, howMany, 14);
    --howMany;

    return 0;
}

我得到的输出:

Beginning processing. Array is currently: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Processing done. Array is currently: 0 1 2 3 4 1866386284 6 7 8 9 10 11 12 13 15 16 17 18 19

然后程序在free (*array); 行崩溃。 我希望我的第二行是 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19。

我该如何解决我的问题?

【问题讨论】:

  • 未定义的行为
  • 内容到底是在什么时候出错?这是导致错误的前一行。 BTW:memmove()的重点是源和目标可以重叠,因为你复制到新内存,你可以使用memcpy()
  • 考虑如果indexToRemove 为零会发生什么。第一个memmove() 复制一个数据结构(当它不应该复制时),第二个将sizeOfArray 结构复制到包含sizeOfArray-1 此类结构的缓冲区/数组中。因此,即使在那种简单的情况下,行为也是未定义的。简而言之:你需要更好地检查你的界限。
  • @Peter 我只是在第一个 memmove() 之前添加了if(indexToRemove &gt; 0),在第二个之前添加了if(indexToRemove &lt; sizeOfArray - 1),这应该是为了边界吗?
  • @Drakalex.:我添加了一个编辑。如果你使用 0 索引应该遵循这些

标签: c arrays pointers struct dynamic-allocation


【解决方案1】:

轻轻一点

删除任何类型的结构数组中的元素

问候

int remove_element(void **input_ptr, int input_size, int index_remove, int struct_size)
{
    void *temp_ptr;

    temp_ptr = malloc((input_size - 1) * struct_size);
    if (temp_ptr == 0)
        return -1;

    memmove(temp_ptr, *input_ptr, index_remove * struct_size);

    memmove(temp_ptr + (index_remove * struct_size), (*input_ptr) + (index_remove + 1) * struct_size, (input_size - index_remove - 1) * struct_size);

    free(*input_ptr);

    *input_ptr = temp_ptr;

    return 1;
}

问题结构的使用示例

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

typedef struct Entity
{
    int x, y;
    int velX, velY;
}Entity;

int remove_element(void **input_ptr, int input_size, int index_remove, int struct_size)
{
    void *temp_ptr;

    temp_ptr = malloc((input_size - 1) * struct_size);
    if (temp_ptr == 0)
        return -1;

    memmove(temp_ptr, *input_ptr, index_remove * struct_size);

    memmove(temp_ptr + (index_remove * struct_size), (*input_ptr) + (index_remove + 1) * struct_size, (input_size - index_remove - 1) * struct_size);

    free(*input_ptr);

    *input_ptr = temp_ptr;

    return 1;
}

int main()
{
    int i;
    int howMany = 20;

    Entity* test = malloc(howMany * sizeof(Entity));

    for (i = 0; i < howMany; ++i)
    {
        (test[i].x) = i;
        printf("test[%d].x = '%d'\n", i, test[i].x);
    }

    remove_element((void**)&test, howMany, 14, sizeof(Entity));
    --howMany;

    printf("Deleted index --- new array\n");
    for (i = 0; i < howMany; ++i)
        printf("test[%d].x = '%d'\n", i, test[i].x);

    return 0;
}

【讨论】:

    【解决方案2】:

    在 main 本身中,你的内存分配没有正确完成。如果你使用双指针,你应该先为双指针分配内存,然后在循环中一个接一个地分配单指针。

    【讨论】:

    • 不是双指针 (Entity* test = ...) 然后将test地址传递给remove_element
    • Entity* test = malloc(howMany * sizeof(Entity*)); for (i = 0; i
    • 正是...在Entitytest 之间您看到多少'*'
    • 您通过将 *Entity 的大小和实体的大小相乘来分配内存,因为它是地址。无法理解是为结构元素还是结构指针分配内存的想法。目前此代码无效。
    【解决方案3】:

    在两个 memmove 实例中,您的偏移量计算值都相差 1。改用这个:

    // copy everything BEFORE the index
    memmove(temp,
            *array,
            indexToRemove * sizeof(Entity));
    
    // copy everything AFTER the index
    memmove(temp + indexToRemove,
            *array + indexToRemove + 1,
            (sizeOfArray - indexToRemove - 1) * sizeof(Entity));
    

    【讨论】:

      【解决方案4】:

      首先你已经分配了内存空间来存放 20 Enity*。然后您取消了它的引用(并且它包含的值是不确定的)。这是未定义的行为。所有的故事到此结束。

      但是让我们分析一下你最想要的。

      Entity* test = malloc(howMany * sizeof(Entity));
                                             ^^^^^^^
      

      是你想要的。因为只有这样做,您才会获得成员元素x 等等。

      此外,如果您正在考虑对 0 进行索引,那么 memmove 调用应该是

      memmove(temp, *array, (indexToRemove)*sizeof(Entity)); 
      memmove(temp+indexToRemove, (*array)+(indexToRemove+1), 
                  (sizeOfArray - indexToRemove - 1)*sizeof(Entity)); 
      

      这两项更改足以解决您面临的问题并实现正确的行为。 (如果这就是您的代码中的全部内容)。

      同样按照标准,main() 应该这样声明,以防它不带任何参数int main(void)。完成使用后释放动态分配的内存。您还应该检查 malloc 的返回值 - 如果它失败,它会返回 NULL 并且您应该处理这种情况。

      【讨论】:

      • 这解决了第一个问题,我的新数组是我想要的,但它仍然在free (*array); 行崩溃
      • 在你的第二个 memmove 中,不应该是temp+indexToRemove*sizeof(Entity)(和第二个参数类似)吗?
      • @StephanLechner.: 不,它不需要......指针算法由它指向的内容决定......所以它会自己移动那么多块。
      • @coderredoc 谢谢你终于成功了!你改变了什么?
      • @Drakalex.:您之前的代码在第二个memmove 中也出现了一个错误。这就是我纠正的。 (sizeOfArray - indexToRemove ) --> (sizeOfArray - indexToRemove - 1)
      猜你喜欢
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多