C语言 我想知道从数组中删除后的值在哪里?



假设我有一个数组

int size=6;
int a[size]={0,1,2,3,4,5};

,我想删除k=3的元素。

for(i=k;i<size-1;i++)
a[k]=a[k+1];
size=size-1;

这里我只是从索引k中删除了元素,可以肯定的是,这个值不会出现在数组中,但如果不在数组中,那么数据在哪里,那个值。

未删除任何内容。

a[k]=a[k+1];行将a[k]的值设置为a[k+1]的值

因此,如果数组以{0,1,2,3,4,5}开始并且k为3,则随后数组保存{0,1,2,4,4,5}

不能"delete"项,只需用其他数据覆盖它们即可。C接近硬件,在物理RAM中没有"删除";单元格的状态,它必须始终保存一个值。

因此,删除一个项目是通过将所有项目移动到您希望删除的项目后面一步来完成的(这是非常低效的)。但是分配的大小仍然是相同的。因此,您需要一个计数器变量来跟踪实际使用的数据大小。

  • 给定一个数组int array[]={0,1,2,3,4,5};

  • 则项目数为sizeof array / sizeof *array;

    size_t items = sizeof array / sizeof *array;
    

    items将是上述计数器变量。

  • 我们希望删除某索引处的一项:

    size_t index = 3;
    
  • 您希望删除的项目后面的块的大小然后表示为:

    size_t size_to_move = (items-index-1) * sizeof *array;
    

    在32位计算机上是(6-3-1)* 4 = 8字节

  • 我们在同一个数组内移动数据,这意味着存在重叠的内存段。在重叠的情况下,我们不能使用memcpy,所以我们必须使用专门的函数memmove来代替,它在内部使用临时缓冲区来处理重叠。

完整例子:

#include <stdio.h>
#include <string.h>
int main() 
{
int array[]={0,1,2,3,4,5};
size_t items = sizeof array / sizeof *array;
size_t index = 3;
size_t size_to_move = (items-index-1) * sizeof *array;

memmove(&array[index], &array[index+1], size_to_move);
items--;
for(size_t i=0; i<items; i++)
{
printf("%d ", array[i]);
}
}

输出:

0 1 2 4 5

注意,如果我们不减少item--的项目计数器,我们将得到0 1 2 4 5 5。分配的数组大小仍然是6,所以我们仍然可以访问最后一个项目,而这个项目用来保存5,所以它仍然包含它,因为项目实际上没有"移动"。但复制。

在C语言中,数组有固定的大小。这意味着既不能向数组中添加元素,也不能从数组中删除元素。你只能重写它们。

最接近动态大小的数组是通过malloc获得的动态数组。它可以稍后通过realloc调整大小,但是:

  • 标准库可以自由地忽略任何收缩调用并保持数组的最大大小
  • 释放的内存可以返回给操作系统,供其他进程访问,也可以保留在当前进程
  • 中。扩展调用可以包含现有元素的完整副本

重新分配动态数组确实是C语言中常见的习惯用法,但您必须意识到它的局限性,不要滥用它。在你的例子中,这是多余的。


动态分配的内存必须由free释放。调用free后:

  • 指针保持其先前的值,被称为dangling指针,因为它指向未分配的内存,解引用它会显式地调用未定义行为(C程序员的地狱…)

  • 标准库的实现可以自由地对释放的内存做任何事情:

    • 它可以返回到操作系统
    • 可以回收以供以后的malloc调用使用,甚至不再可用。用于管理动态内存的底层算法未由标准
    • 指定。

也就是说,一种常见的算法是与操作系统交换一定大小的,并从这些页为程序分配内存。空块通常作为列表处理,新释放的块与相邻的空闲块连接,以尝试拥有尽可能大的块。只有当页面被包含在一个free bloc中时,它才能返回到操作系统。但这是标准库实现者的问题,而不是C程序员的问题。

最新更新