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

C语言结构体数组删重名元素:deleteAnimalByName仅删除单个对象问题排查

核心问题定位

原删除函数存在两处逻辑错误,直接导致重名条目无法被全部删除:

  • 元素移位逻辑笔误:原本需要将j+1位置的元素拷贝到j位置完成前移,却误写成了j+i作为源索引,不仅移位动作完全错位,还可能引发数组越界、数据随机覆盖的问题。
  • 遍历逻辑缺陷:当匹配到目标条目并完成前移、更新数组长度后,外层循环会直接将索引i自增,跳过了当前i位置被新元素填充的位置——刚好这个位置就可能是之前未被检查到的同名条目,最终造成漏删。
修复方案

基础修正版(兼容原代码逻辑框架)

调整遍历的索引递增规则:仅当当前位置元素不匹配删除条件时,才推进遍历索引;匹配删除后不推进索引,重新检查当前位置新挪入的元素,同时修正移位的源索引为正确的j+1:

void deleteAnimalByName(char *animalName, int *nrOfAnimals, ANIMAL *animalArray)
{
    int i = 0;
    while (i < *nrOfAnimals)
    {
        if (strcmp(animalArray[i].Name, animalName) == 0)
        {
            // 将后续元素整体前移覆盖当前匹配位置
            for (int j = i; j < *nrOfAnimals - 1; j++)
            {
                animalArray[j].Age = animalArray[j + 1].Age;
                strcpy(animalArray[j].Name, animalArray[j + 1].Name);
                animalArray[j].Species = animalArray[j + 1].Species;
            }
            // 更新有效数组长度
            (*nrOfAnimals)--;
            // 不推进索引,下一轮直接检查挪到当前i位置的新元素
            continue;
        }
        // 无匹配时才推进索引
        i++;
    }
}

优化版(双指针实现,效率更高)

原逻辑每删除一个元素就要整体拷贝后续所有元素,时间复杂度最坏为O(n²)。可以用读写双指针一次遍历完成筛选:读指针遍历全部有效元素,遇到需要保留的非同名元素就写入写指针位置,遍历完成后直接将数组有效长度设为写指针的位置,无需反复移位:

void deleteAnimalByName(char *animalName, int *nrOfAnimals, ANIMAL *animalArray)
{
    int writePos = 0;
    // 遍历所有有效元素
    for (int readPos = 0; readPos < *nrOfAnimals; readPos++)
    {
        // 保留非同名元素
        if (strcmp(animalArray[readPos].Name, animalName) != 0)
        {
            // 同类型结构体直接赋值,替代逐个成员拷贝
            animalArray[writePos] = animalArray[readPos];
            writePos++;
        }
    }
    // 更新有效数组长度
    *nrOfAnimals = writePos;
}

注意:该优化版要求ANIMAL结构体可直接赋值(即不含动态内存指针成员),若结构体包含指向堆内存的指针,需替换为逐个成员的深拷贝逻辑,避免浅拷贝导致的内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 11:06:04