当C中有多个同名记录时如何删除记录
Posted
技术标签:
【中文标题】当C中有多个同名记录时如何删除记录【英文标题】:How to delete a record when there's more than one record of the same name in C 【发布时间】:2021-09-28 21:24:39 【问题描述】:我正在为 s 献血系统编写代码。我目前正在为删除捐赠者记录功能而苦苦挣扎。
删除记录功能是删除一个给定名字的捐赠者的记录。如果文件中有两个或多个同名记录,则程序会要求提供手机号码。虽然可能有不止一个人同名,但每个人都有一个唯一的手机号码。
我的问题是多条记录使用同名时,删除了错误的记录。
如果只有一条具有该名称的记录,则程序会以所需的方式删除该记录。
(变量 i 全局声明为 int i)
这里是删除功能
void delete(struct blood *b,int n)
char name[50];
int phone;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
if(strcmpi(b[i].name,name)==0)
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
if (c==1)
found=1;
else if(c>1)
printf("\nThere are more than one occurences of this name in the records\n");
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
if (b[i].phone == phone)
found=1;
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
fclose(fp);
fclose(fp1);
if (found==1)
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
fwrite(&b[i],sizeof(struct blood),1,fp);
fclose(fp);
fclose(fp1);
else
printf("\n\aRECORD DOES NOT EXIST.\n");
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
【问题讨论】:
我认为您需要分多个步骤执行此操作:首先找到并计算“命中”的数量。然后在第二步中,根据条件查找和擦除。scanf(" %[^\n]s", name);
与dangerous as gets
相同,因为您可以轻松读取超出缓冲区容量的数据。还知道%[]
和%s
是两个独立的转换说明符,您不要将它们组合在一起。始终指定最大长度 %49[^\n]
,即缓冲区的长度 - 1。(考虑使用涉及 fgets
的更强大的方法)。
这些是文本文件吗(.txt 扩展名暗示了这一点)?如果是这样,那么fwrite
不合适。
Aditya Ranjan,谁或什么文字建议scanf(" %[^\n]s", name);
?
@Aditya Ranjan - 作为函数的第一个参数传递的内容。 i
的定义及其在调用时的值是什么?
【参考方案1】:
我建议为了简化程序,您在开始时要求捐赠者的姓名和捐赠者的手机号码。
然后您处理输入文件并一次性查找姓名和手机号码。
我从您的代码开始并进行了一些更改。见 cmets。
请注意,我没有测试过这段代码,也没有编译过它。它基本上应该是正确的,但是如果我犯了语法错误,可能会出现编译器错误。
我假设您在代码中正确使用了struct blood
,因为您没有提供定义该结构的代码。
我假设int
足够大,可以容纳手机号码。由于int
的大小可能会有所不同并且由编译器确定,因此对于手机号码而言,它可能足够大,也可能不够大。见Range of values in C Int and Long 32 - 64 bits
我不明白的一件事是您为什么使用b[i]
语法以及变量i
定义在哪里?您可以改为在 delete()
函数中使用局部变量。
我还有 delete()
函数返回一个值,指示它是否找到匹配项。这可能有用,也可能没用。
int delete()
struct blood b;
char name[50] = 0;
int phone;
int found = 0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
// Ask for the donor's mobile number along with their name
// at the beginning to make the search easier and be able to
// do this in a single pass.
printf("\nEnter Name of the donor: ");
scanf("%49s", name); // Oka's comments about scanf().
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
printf("---------------------------------------------\n");
while(fread(&b, sizeof(struct blood), 1, fp))
// check both donor's name and donor's mobile number.
if(strcmpi(b.name, name) == 0 && b.phone == phone)
// print out the donor data and indicate we are deleting
// this donor record.
printf("Deleting donor record\n");
printf(" Name: %s\n", b.name);
printf(" Age: %d\n", b.age);
printf(" Mobile no.: %d\n", b.phone);
printf(" Blood group: %s\n", b.bg );
printf(" Weight: %d\n", b.weight);
printf(" Sex: %s\n", b.sex);
printf(" Address: %s\n", b.add);
printf("\n");
found = 1;
else
// we are keeping this donor record so write it to the
// temp file.
fwrite(&b, sizeof(struct blood), 1, fp1);
fclose(fp);
fclose(fp1);
if (found == 1)
// file temp.txt has deleted donors so lets updated
// the original file, bloodrecord.txt, with the updated
// list of donors.
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b, sizeof(struct blood), 1, fp1))
fwrite(&b, sizeof(struct blood), 1, fp);
fclose(fp);
fclose(fp1);
printf("RECORD SUCCESSFULLY DELETED");
else
printf("\n\aRECORD DOES NOT EXIST.\n");
getchar();
getchar();
return found; // indicate if we found a match or not.
【讨论】:
旁白:不要考虑fread(&b, sizeof(struct blood), 1, fp1)
和其他人,而是考虑fread(&b, sizeof b, 1, fp1)
。使用sizeof(struct blood)
,需要查看代码以查看是否使用了正确的类型。如果b
的类型发生变化,则需要做更多的工作来更新代码。 sizeof b
修复了这两个问题。
@chux-ReinstateMonica 这是一个很好的观点。谢谢。【参考方案2】:
我重用了您的大部分代码,并添加了第二遍来处理实际删除(第一遍搜索匹配的记录)。
void delete(struct blood *b,int n)
const int MOBILE_SIZE = 16;
char name[50];
int phone = 0;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
if(strcmpi(b[i].name,name)==0)
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
found = 1;
/* Finished the first pass. Now, start again */
rewind(fp)
if (c > 1)
printf("There are multiple records for the name %s\n", name);
printf("\nEnter Mobile Number: ");
scanf("%d", &phone);
while(fread(&b[i],sizeof(struct blood),1,fp))
if((c == 1 && strcmpi(b[i].name,name)==0)
|| (c > 1 && strcmpi(b[i].name,name) == 0 && b[i].mobile == mobile))
continue; /* skip this record */
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
fclose(fp);
fclose(fp1);
if (found==1)
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
fwrite(&b[i],sizeof(struct blood),1,fp);
fclose(fp);
fclose(fp1);
else
printf("\n\aRECORD DOES NOT EXIST.\n");
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
【讨论】:
scanf("%s", name);
教别人是一种非常糟糕的做法。见我上面的评论。您至少必须使用字段宽度说明符 scanf("%49s", name);
,以确保此代码安全。即使这样它也很容易出错,必须维护两个幻数。以上是关于当C中有多个同名记录时如何删除记录的主要内容,如果未能解决你的问题,请参考以下文章
当引用表中没有匹配的记录时,delete语句如何与REFERENCE约束冲突?