You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过指针从数组中删除指定元素且不移动其余元素

如何在不移动数组元素的情况下,遍历输出除指定位置外的所有元素(结合指针实现)

刚接触指针的话,咱们先把几个关键概念掰扯清楚,再一步步实现你要的效果~首先得明确:你说的“删除第n个元素但不左移其余元素”,其实是逻辑删除——也就是原数组的内存布局完全不动,只是遍历的时候跳过那个元素就行,不是真的从内存里把它删掉(毕竟数组是连续内存,单独删一个元素不移动后面的话,会留下内存空洞,而且栈上的数组根本没法这么操作,堆数组也不能单独用free()删单个元素)。

一、先搞懂:为什么free()帮不上忙?

  • 首先,free() 函数的作用是释放整个由堆内存分配函数(malloc/calloc/realloc)分配的内存块,它管不了栈上的内存,也不能拆开来释放堆内存块里的某一部分。
  • 比如你用 int *arr = malloc(6 * sizeof(int)); 分配了一个能存6个int的堆数组,free(arr) 会把整个6个int的内存块都释放,但你要是写 free(&arr[2]) 想单独删第3个元素——这会直接导致未定义行为,程序大概率崩溃或者出各种奇怪的问题。
  • 所以你的需求里,free() 完全用不上,咱们重点看指针的实现方式。

二、用指针实现:遍历跳过指定元素

不管你的数组是栈上定义的,还是堆上分配的,都能用指针来遍历,并且跳过指定索引的元素(这里咱们统一用从0开始的索引,比如你例子里要删除的“第2个元素”如果是指原数组里的6,那对应的索引就是2)。

方法1:最直接的指针遍历+判断

这是最简单的方式,遍历数组的时候,只要当前指针没指向要跳过的元素,就打印它,原数组完全不动。

代码示例:

#include <stdio.h>

int main() {
    // 原数组(栈上定义的数组)
    int arr[] = {4, 7, 6, 2, 9, 5};
    int skip_idx = 2; // 要跳过的元素索引(对应原数组的6)
    int arr_len = sizeof(arr) / sizeof(arr[0]); // 计算数组长度

    // 用指针指向数组开头
    int *ptr = arr;
    // 遍历整个数组:ptr从数组开头,一直走到数组尾后指针
    for (; ptr < arr + arr_len; ptr++) {
        // 如果当前指针不是指向要跳过的元素,就打印
        if (ptr != &arr[skip_idx]) {
            printf("%d ", *ptr);
        }
    }
    printf("\n");

    return 0;
}

运行后输出就是你要的:4 7 2 9 5,原数组的元素位置完全没动。

代码细节解释:

  • int *ptr = arr;:数组名arr本质上就是指向数组第一个元素的指针,所以把它赋值给ptr,让ptr一开始就指向数组开头。
  • ptr < arr + arr_len:arr + arr_len是数组的“尾后指针”——也就是指向最后一个元素的下一个位置的指针,这个循环条件能保证咱们遍历完数组里的所有元素。
  • ptr != &arr[skip_idx]:&arr[skip_idx]是你要跳过的元素的内存地址,当当前指针ptr不等于这个地址时,就解引用指针(*ptr)拿到元素值并打印。

方法2:用指针数组保存需要保留的元素(适合多次使用“过滤后数组”)

如果你后续还要多次用到“删除指定元素后的数组”,可以用一个指针数组来保存所有需要保留的元素的地址,这样之后直接遍历这个指针数组就能输出,原数组还是完全不变。

代码示例:

#include <stdio.h>

int main() {
    int arr[] = {4, 7, 6, 2, 9, 5};
    int skip_idx = 2;
    int arr_len = sizeof(arr) / sizeof(arr[0]);
    // 定义一个指针数组,长度是原数组长度减1(因为要跳过一个元素)
    int *filtered[arr_len - 1];
    int filtered_idx = 0;

    // 填充指针数组:把不需要跳过的元素的地址存进去
    for (int i = 0; i < arr_len; i++) {
        if (i != skip_idx) {
            filtered[filtered_idx++] = &arr[i];
        }
    }

    // 遍历指针数组输出
    for (int i = 0; i < arr_len - 1; i++) {
        printf("%d ", *filtered[i]);
    }
    printf("\n");

    return 0;
}

这个方法里,filtered数组的每个元素都是指向原数组中有效元素的指针,输出的时候只要解引用这些指针就行,原数组的内存布局一点没变。

三、堆数组的操作逻辑完全一样

如果你是用堆内存分配的数组(比如动态创建的数组),操作逻辑和栈数组完全一致,比如:

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

int main() {
    // 堆上分配的数组,能存6个int
    int *arr = malloc(6 * sizeof(int));
    if (arr == NULL) { // 别忘了判断malloc是否成功
        printf("内存分配失败\n");
        return 1;
    }
    // 给数组赋值
    arr[0] = 4; arr[1] =7; arr[2]=6; arr[3]=2; arr[4]=9; arr[5]=5;

    int skip_idx = 2;
    int arr_len = 6; // 堆数组没法用sizeof计算长度,得自己记录

    // 指针遍历跳过指定元素
    int *ptr = arr;
    for (; ptr < arr + arr_len; ptr++) {
        if (ptr != &arr[skip_idx]) {
            printf("%d ", *ptr);
        }
    }
    printf("\n");

    free(arr); // 堆数组用完一定要释放整个内存块
    return 0;
}

唯一的区别是堆数组需要自己记录长度(没法用sizeof计算),用完后要用free(arr)释放整个内存块,依然不能单独释放某个元素。

总结一下

  • free() 不能用来删除数组中的单个元素,只能释放整个堆内存块,所以你的需求里用不到它。
  • 要实现“不移动元素,遍历输出除指定位置外的所有元素”,最直接的方式就是用指针遍历数组,判断当前指针是否指向要跳过的元素,符合条件就输出。
  • 这种方式属于逻辑删除,原数组的内存布局完全不变,完美满足你的要求。

内容的提问来源于stack exchange,提问作者user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:50:08