c - 请帮我看看为什么这个程序在第二次执行时会出错
问题描述
想搭建一个小系统输入消费者信息,但是添加新信息的功能有bug。第一次可以正常添加,但第二次添加会无限添加结果。如图,有文件信息和程序。
先做一些处理
#include <stdio.h>
#include <stdlib.h>
//Create structure
struct stu_con {
long time;
int num; //student ID
char name[10];
double money;
struct stu_con *next;
};
struct stu_con *head;//Global variable head pointer
//Create a linked list and enter the file into the linked list
struct stu_con *create(struct stu_con *head) {
FILE *fp;
struct stu_con *p1, *p2, *p;
if ((fp = fopen("d:\\fee.txt", "r+")) == NULL) { //Open a D drive file
printf("Cannot open file!\n");
exit(0);
} else {
printf("Successfully opened the file!\n");
head = p1 = p2 = (struct stu_con *)malloc(sizeof(struct stu_con));
while ((fscanf(fp, "%d%d%s%lf", &p1->time, &p1->num, p1->name, &p1->money)) != EOF) { //getting information
p1 = (struct stu_con *)malloc(sizeof(struct stu_con));
p2->next = p1;
p2 = p1;
}
p1->next = NULL;
p1 = p2 = head;
while (p1->next != NULL) {
p2 = p1;
p1 = p1->next;
}
p2->next = NULL;
printf("The file is entered successfully!\n");
fclose(fp);
}
return head;
};
//Show the contents of the file
void show(struct stu_con *head) {
struct stu_con *p;
p = head;
while (p != NULL) {
printf("%d\t%d\t%s\t%.2lf\n", p->time, p->num, p->name, p->money);
p = p->next;
}
}
那么问题就在这里
//Add new information
struct stu_con *insert(struct stu_con *head, struct stu_con *bo) {
struct stu_con *p0, *p1, *p2;
p1 = head;
p0 = bo;
if (head == NULL) {
head = p0;
p0->next = NULL;
} else {
//According to the time to determine the location to join
while ((p0->time > p1->time) && (p1->next != NULL)) {
p2 = p1;
p1 = p1->next;
}
if (p0->time <= p1->time) {
if (head == p1)
head = p0;
else
p2->next = p0;
p0->next = p1;
} else {
p1->next = p0;
p0->next = NULL;
}
}
return head;
};
最后是main函数
//Main function
int main() {
struct stu_con bo;
head = create(head); //Create a linked list
show(head);
again_n: //Build a loop
printf("Please enter the student consumption information record you want to add:\n");
scanf("%d%d%s%lf", &bo.time, &bo.num, bo.name, &bo.money);
head = insert(head, &bo);
printf("The information is entered successfully. \n"
"Do you want to continue to enter it?(Y/N):");
getchar();
while (getchar() == 'Y')
goto again_n; //Loop
show(head); //Show results
return 0;
}
希望有人可以帮助我,谢谢
解决方案
您的代码中有多个问题:
- 您的列表构造不正确:您总是在尝试从文件中读取更多输入之前分配一个新的未初始化节点。列表中的最后一个节点总是虚假的,在您的代码中删除它很麻烦。您应该改为将输入读入局部变量,并且仅在成功时分配一个新节点,添加到列表的尾部,并保留指向列表的第一个和最后一个元素的指针。
fscanf()
返回成功转换的次数。您应该进行比较fscanf(...) == 4)
以正确检测转换错误。- 该文件应该以
"r"
,"r+"
是更新模式打开以供读取,这在此处使用起来相当棘手且不必要。 %s
是一个有风险的转换fscanf()
。您应该将要存储到目标数组中的最大字符数指定为%9s
.- 在
main()
您插入一个作为局部变量的结构main
而不是分配的对象。这是不好的风格并且容易出错。您应该编写一个函数来分配一个新结构并将其插入列表中并使用它create
。 - 不要使用标签和条件
goto
,而是使用for(;;)
循环和条件break
语句。 - 你应该使用
%ld
它time
同时具有long
inprintf
和scanf
. - 而不是传递
head
和重新调整更新的值,而是传递一个指针head
并返回一个成功指示器。
这是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
//Create structure
struct stu_con {
long time;
int num;//student ID
char name[10];
double money;
struct stu_con *next;
};
// Allocate a new structure and insert it in the list
struct stu_con *insert_stu(struct stu_con **head, const struct stu_con *stu) {
struct stu_con *new_stu = malloc(sizeof(*new_stu));
struct stu_con **pp;
if (new_stu) {
*new_stu = *stu;
/* find the insertion position in increasing order of time */
for (pp = head; *pp && (*pp)->time <= new_stu->time; pp = &(*pp)->next)
continue;
new_stu->next = *pp;
*pp = new_stu;
}
return new_stu;
}
// Load records from a file and insert in the list
int load_file(struct stu_con **head, const char *filename) {
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL) {
printf("Cannot open file %s!\n", filename);
return 0;
} else {
char buf[100];
struct stu_con stu;
printf("Successfully opened the file %s!\n", filename);
while (fgets(buf, sizeof buf, fp)) {
if (sscanf(buf, "%ld%d%9s%lf", &stu.time, &stu.num, stu.name, &stu.money) == 4)
insert_stu(head, &stu);
else
printf("Invalid record: %s", buf);
}
printf("The file %s is entered successfully!\n", filename);
fclose(fp);
return 1;
}
}
//Show the contents of the file
void show(const struct stu_con *p) {
while (p != NULL) {
printf("%ld\t%d\t%s\t%.2f\n", p->time, p->num, p->name, p->money);
p = p->next;
}
}
//Main function
int main() {
char buf[100];
struct stu_con stu;
struct stu_con *head = NULL; //Local variable head pointer, empty list
load_file(&head, "fee.txt"); // cannot use "d:\\fee.txt" for testing
for (;;) {
printf("Please enter the student consumption information record you want to add:\n");
if (!fgets(buf, sizeof buf, stdin))
break;
if (sscanf(buf, "%ld%d%9s%lf", &stu.time, &stu.num, stu.name, &stu.money) == 4) {
if (insert_stu(&head, &stu))
printf("The information is entered successfully.\n");
} else {
printf("Invalid data: %s", buf);
}
printf("Do you want to continue to enter it?(Y/N):");
if (!fgets(buf, sizeof buf, stdin) || *buf != 'Y')
break;
}
// Show the resulting list
show(head);
// Free the list
while (head) {
struct stu_con *next = head->next;
free(head);
head = next;
}
return 0;
}
推荐阅读
- java - Spring Data - 无法执行 CommandLineRunner
- tensorflow - 使用 tensorflow session.run() 进行预测和使用 tf-serving 进行预测的性能有何不同?
- java - 错误:无法在 bash 上找到或加载主类 pj2
- python - Apache Beam/Google 数据流 Python 流式自动缩放
- twitter - Twitter 搜索 API 响应?
- solr - Solr:AND 查询奇怪的行为,没有正确过滤
- sql - SQL将日期时间转换为varchar
- parsing - 检测文本中对表格和图像的引用。
- javascript - 如何将字符串转换为数字并确保 JavaScript 中的浮点类型?
- java - 如何为网络通话设置同步?