如何通过指针从数组中删除指定元素且不移动其余元素
如何在不移动数组元素的情况下,遍历输出除指定位置外的所有元素(结合指针实现)
刚接触指针的话,咱们先把几个关键概念掰扯清楚,再一步步实现你要的效果~首先得明确:你说的“删除第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
相关产品推荐
相关产品推荐

