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);行崩溃,预期输出应该是删除索引14后的完整序列。
错误分析与修复方案
1. 内存分配错误(main函数核心问题)
你初始化动态数组时,错误地使用了sizeof(Entity*)而非sizeof(Entity):
Entity* test = malloc(howMany * sizeof(Entity*)); // 错误!
test是指向Entity结构体的指针,每个数组元素是完整的Entity结构体,不是指针类型。用sizeof(Entity*)会导致分配的内存仅为实际需要的1/2或1/4(取决于系统位数),后续的赋值、拷贝操作都会触发内存越界访问,这也是程序free时崩溃的根本原因。
2. memmove拷贝长度计算错误
在remove_element函数中,第二个memmove的拷贝字节数计算有误:
memmove( temp+indexToRemove, (*array)+(indexToRemove+1), (sizeOfArray - indexToRemove)*sizeof(Entity)); // 错误!
要拷贝的是indexToRemove之后的所有元素,元素数量应为sizeOfArray - indexToRemove - 1(总元素数减去要删除的1个,再减去前半部分已拷贝的indexToRemove个)。之前的计算多了一个元素的大小,导致越界读取内存垃圾值,也就是你看到的1866386284。
修正后的完整代码
#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) { // 增加非法索引检查 if (indexToRemove < 0 || indexToRemove >= sizeOfArray) { printf("Error: Invalid index to remove!\n"); return -1; } 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)); if (!temp) { perror("Failed to allocate memory"); return -1; } // 拷贝前半部分:0 到 indexToRemove-1 memmove(temp, *array, indexToRemove * sizeof(Entity)); // 拷贝后半部分:indexToRemove+1 到 sizeOfArray-1 memmove(temp + indexToRemove, (*array) + indexToRemove + 1, (sizeOfArray - indexToRemove - 1) * sizeof(Entity)); 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; // 修正内存分配的sizeof参数 Entity* test = malloc(howMany * sizeof(Entity)); if (!test) { perror("Failed to allocate memory"); return 1; } for (i = 0; i < howMany; ++i) test[i].x = i; // 仅当删除成功时更新数组长度 if (remove_element(&test, howMany, 14) == 0) { --howMany; } // 最后释放内存,避免泄漏 free(test); 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 5 6 7 8 9 10 11 12 13 15 16 17 18 19
程序也不会再崩溃,同时我还增加了内存分配失败检查、非法索引检查,以及最终的内存释放,提升了代码的健壮性。
内容的提问来源于stack exchange,提问作者Drakalex
相关产品推荐
相关产品推荐

