C语言如何将NameCard结构体数组按nameCardID升序排列
问题分析
- 临时数组
fakeHolder使用逻辑错误:仅将新名片存入fakeHolder[0],遍历原有数组时仅拷贝了ID大于新ID的元素到临时数组,ID小于新ID的元素完全没有拷贝到临时数组中,导致这部分数据丢失,最终排序结果错误。 - ID重复校验逻辑不完整:检测到ID重复后仅打印提示,没有终止后续的新增流程,重复ID仍会被插入到数组中,且
size会错误累加。 - 插入逻辑缺失位置判断:没有提前确定新ID的插入位置,边遍历边拷贝的逻辑无法覆盖所有排序场景,连续插入更小的ID时数据顺序会完全混乱。
- 临时数组固定长度风险:
fakeHolder固定长度为10,若业务定义的最大名片数MAX大于10,会出现数组越界访问。
正确实现思路
不需要额外申请完整的临时数组,仅用单个临时结构体存储新录入的名片即可,插入逻辑如下:
- 首先判断当前名片数是否已达上限,满员直接返回。
- 录入新名片信息存储到临时结构体,先校验ID是否已存在,存在则直接返回不新增。
- 遍历现有有序数组,找到第一个大于新ID的元素下标
pos,即为新名片的插入位置;若所有现有ID都小于新ID,pos等于当前名片数,直接追加到末尾。 - 将数组中从
pos开始到末尾的所有元素统一向后挪动1位,空出pos位置。 - 将临时结构体的内容赋值到
pos位置,名片数+1,完成升序插入。
修正后代码
#include <stdio.h> #include <string.h> #define MAX 50 // 可根据业务需求调整最大名片数 typedef struct{ int nameCardID; char personName[20]; char companyName[20]; } NameCard; int addNameCard(NameCard *nc, int *size){ printf("addNameCard():\n"); if(*size == MAX){ printf("The name card holder is full\n"); return 0; } // 仅用单个临时结构体存储新名片 NameCard newCard; char dummy; char *p; printf("Enter nameCardID:\n"); scanf("%d", &newCard.nameCardID); scanf("%c", &dummy); // 吃掉输入缓冲区的换行符 printf("Enter personName:\n"); fgets(newCard.personName, 20, stdin); if((p = strchr(newCard.personName, '\n')) != NULL){ *p = '\0'; } printf("Enter companyName:\n"); fgets(newCard.companyName, 20, stdin); if((p = strchr(newCard.companyName, '\n')) != NULL){ *p = '\0'; } // 第一步:校验ID是否重复 for(int j = 0; j < *size; j++){ if(newCard.nameCardID == nc[j].nameCardID){ printf("The nameCardID has already existed\n"); return 0; // 重复直接返回,不执行新增 } } // 第二步:找到插入位置pos int pos = 0; while(pos < *size && nc[pos].nameCardID < newCard.nameCardID){ pos++; } // 第三步:将pos及之后的元素向后挪一位 for(int j = *size; j > pos; j--){ nc[j] = nc[j-1]; // 结构体可直接赋值,不需要逐字段拷贝 } // 第四步:插入新名片,size+1 nc[pos] = newCard; *size += 1; printf("The name card has been added successfully\n"); return 0; }
上述代码利用C语言结构体支持直接赋值的特性简化了字段拷贝逻辑,插入的时间复杂度为O(n),适合名片数不大的场景。如果名片数规模很大,可以用二分查找优化插入位置的查找效率。
内容的提问来源于stack exchange,提问作者Michelin_Boi
相关产品推荐
相关产品推荐

