双链表。我做的还好吗?
我是 C 编程的初学者。我的任务是使用双链表创建学生列表。该应用程序应该有三点:显示列表、添加新学生和通过学生 ID 号删除学生。 我做到了并且运行得很好。 我想问几个问题:
- 使用的东西是否不合适?
- 如果有缩短代码的空间,我将很高兴收到任何建议。
这是我的代码:
struct student
{
char first_name[20];
char last_name[20];
char ID_NO[14];
struct student* previous;
struct student* next;
};
void Menu();
void Show_List(struct student*);
struct student* Add_Student(char [], char [], char [], struct student*);
struct student* Erase_Student(char [], struct student*);
void main(void)
{
char student_first_name[20];
char student_last_name[20];
char personal_code[14];
struct student* first = NULL;
struct student* node0 = NULL;
int x = 0;
int opt;
Menu();
for(; ;)
{
printf("\nEnter the operation you want to do: \n");
scanf("%d", &opt);
switch(opt)
{
case 1:
Show_List(first);
break;
case 2:
printf("\nEnter the student's first name: ");
scanf("%s", &student_first_name);
printf("\nEnter the student's last name: ");
scanf("%s", &student_last_name);
printf("\nEnter the student's personal code: ");
scanf("%s", &personal_code);
node0 = Add_Student(student_first_name, student_last_name, personal_code, first);
first = node0;
break;
case 3:
printf("\nEnter the code of the student you want to erase: ");
scanf("%s", &personal_code);
node0 = Erase_Student(personal_code, first);
first = node0;
break;
default:
printf("\nYou entered an invalid option!!! Please try again.\n");
Menu();
break;
}
}
scanf("%d", &x);
}
void Menu()
{
printf("\nSelect from the Menu the operation you want to execute:\n");
printf("\n1) Show students list;");
printf("\n2) Add a student in the list;");
printf("\n3) Erase a student from the list.");
}
void Show_List(struct student* firstNode)
{
struct student* firstNodeCopy = firstNode;
int number = 0;
if(firstNode == NULL)
printf("\nThe list is empty.\n");
while(firstNodeCopy)
{
printf("\n%d. %s ", ++number, firstNodeCopy->first_name);
printf("%s %s\n", firstNodeCopy->last_name, firstNodeCopy->ID_NO);
firstNodeCopy = firstNodeCopy->next;
}
}
struct student* Add_Student(char name_1[], char name_2[], char ID[], struct student* firstNode)
{
struct student* start = firstNode;
struct student* last = NULL;
struct student* addNode = (struct student*) malloc(sizeof(struct student));
if(firstNode == NULL)
{
firstNode = (struct student*) malloc(sizeof(struct student));
strcpy(firstNode->first_name, name_1);
strcpy(firstNode->last_name, name_2);
strcpy(firstNode->ID_NO, ID);
firstNode->next = NULL;
firstNode->previous = NULL;
return firstNode;
}
else
{
strcpy(addNode->first_name, name_1);
strcpy(addNode->last_name, name_2);
strcpy(addNode->ID_NO, ID);
while(start)
{
if(strcmp(addNode->first_name, start->first_name) > 0)
{
if(start->next == NULL)
{
start->next = addNode;
addNode->previous = start;
addNode->next = NULL;
return firstNode;
}
else
{
last = start;
start = start->next;
}
}
if(strcmp(addNode->first_name, start->first_name) < 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
if(strcmp(addNode->first_name, start->first_name) == 0)
{
if(strcmp(addNode->last_name, start->last_name) < 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
if(strcmp(addNode->last_name, start->last_name) > 0)
{
if(start->next == NULL)
{
start->next = addNode;
addNode->previous = start;
addNode->next = NULL;
return firstNode;
}
else
{
last = start;
start = start->next;
}
}
if(strcmp(addNode->last_name, start->last_name) == 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
}
}
}
}
struct student* Erase_Student(char ID[], struct student* firstNode)
{
struct student* start = firstNode;
struct student* last = NULL;
if(start == NULL)
{
printf("\nThe list is empty.\n");
return NULL;
}
else
{
while(start)
{
if(strcmp(ID, start->ID_NO) == 0)
{
if(last == NULL)
{
start = start->next;
return start;
}
else
{
last->next = start->next;
return firstNode;
}
}
else
{
last = start;
start = start->next;
}
}
printf("\nYou entered a WRONG personal ID number to erase!!! Please try again.\n");
return firstNode;
}
}
I'm a beginner in C programming. I had a task creating a list of students using a double linked list. The application should have three points: display the list, add a new student and delete a student by his ID number.
I did it and it runs very well.
I would like to ask a few questions:
- Is something used inappropriate?
- If there is room to shorten the code I would be happy to recieve any suggestions.
Here is my code:
struct student
{
char first_name[20];
char last_name[20];
char ID_NO[14];
struct student* previous;
struct student* next;
};
void Menu();
void Show_List(struct student*);
struct student* Add_Student(char [], char [], char [], struct student*);
struct student* Erase_Student(char [], struct student*);
void main(void)
{
char student_first_name[20];
char student_last_name[20];
char personal_code[14];
struct student* first = NULL;
struct student* node0 = NULL;
int x = 0;
int opt;
Menu();
for(; ;)
{
printf("\nEnter the operation you want to do: \n");
scanf("%d", &opt);
switch(opt)
{
case 1:
Show_List(first);
break;
case 2:
printf("\nEnter the student's first name: ");
scanf("%s", &student_first_name);
printf("\nEnter the student's last name: ");
scanf("%s", &student_last_name);
printf("\nEnter the student's personal code: ");
scanf("%s", &personal_code);
node0 = Add_Student(student_first_name, student_last_name, personal_code, first);
first = node0;
break;
case 3:
printf("\nEnter the code of the student you want to erase: ");
scanf("%s", &personal_code);
node0 = Erase_Student(personal_code, first);
first = node0;
break;
default:
printf("\nYou entered an invalid option!!! Please try again.\n");
Menu();
break;
}
}
scanf("%d", &x);
}
void Menu()
{
printf("\nSelect from the Menu the operation you want to execute:\n");
printf("\n1) Show students list;");
printf("\n2) Add a student in the list;");
printf("\n3) Erase a student from the list.");
}
void Show_List(struct student* firstNode)
{
struct student* firstNodeCopy = firstNode;
int number = 0;
if(firstNode == NULL)
printf("\nThe list is empty.\n");
while(firstNodeCopy)
{
printf("\n%d. %s ", ++number, firstNodeCopy->first_name);
printf("%s %s\n", firstNodeCopy->last_name, firstNodeCopy->ID_NO);
firstNodeCopy = firstNodeCopy->next;
}
}
struct student* Add_Student(char name_1[], char name_2[], char ID[], struct student* firstNode)
{
struct student* start = firstNode;
struct student* last = NULL;
struct student* addNode = (struct student*) malloc(sizeof(struct student));
if(firstNode == NULL)
{
firstNode = (struct student*) malloc(sizeof(struct student));
strcpy(firstNode->first_name, name_1);
strcpy(firstNode->last_name, name_2);
strcpy(firstNode->ID_NO, ID);
firstNode->next = NULL;
firstNode->previous = NULL;
return firstNode;
}
else
{
strcpy(addNode->first_name, name_1);
strcpy(addNode->last_name, name_2);
strcpy(addNode->ID_NO, ID);
while(start)
{
if(strcmp(addNode->first_name, start->first_name) > 0)
{
if(start->next == NULL)
{
start->next = addNode;
addNode->previous = start;
addNode->next = NULL;
return firstNode;
}
else
{
last = start;
start = start->next;
}
}
if(strcmp(addNode->first_name, start->first_name) < 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
if(strcmp(addNode->first_name, start->first_name) == 0)
{
if(strcmp(addNode->last_name, start->last_name) < 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
if(strcmp(addNode->last_name, start->last_name) > 0)
{
if(start->next == NULL)
{
start->next = addNode;
addNode->previous = start;
addNode->next = NULL;
return firstNode;
}
else
{
last = start;
start = start->next;
}
}
if(strcmp(addNode->last_name, start->last_name) == 0)
{
if(last == NULL)
{
addNode->next = start;
start->previous = addNode;
return addNode;
}
else
{
addNode->next = start;
addNode->previous = last;
last->next = addNode;
start->previous = addNode;
return firstNode;
}
}
}
}
}
}
struct student* Erase_Student(char ID[], struct student* firstNode)
{
struct student* start = firstNode;
struct student* last = NULL;
if(start == NULL)
{
printf("\nThe list is empty.\n");
return NULL;
}
else
{
while(start)
{
if(strcmp(ID, start->ID_NO) == 0)
{
if(last == NULL)
{
start = start->next;
return start;
}
else
{
last->next = start->next;
return firstNode;
}
}
else
{
last = start;
start = start->next;
}
}
printf("\nYou entered a WRONG personal ID number to erase!!! Please try again.\n");
return firstNode;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
free()
删除的节点。除此之外,逻辑很好。
free()
the removed node.int compareStudents(char * LeftFirstName, char * LeftLastName, char * RightFirstName, char * RightLastName);
Apart from that, the logic is good.
你一切都做得非常好!干得好,刚开始!继续学习。
You did everything perfectly well! Nice job, for the beginning! Keep learning.
这其实非常好!我承认,在你的介绍之后,我希望事情会变得一团糟。
你在那里做得很好,伙计。无论你能改进什么,你都会在适当的时候学到:)。继续这样工作吧!
我本来打算建议您查找什么是“抽象数据类型”,以及如何公开掩盖实现的接口,但正如我所说 - 您很快就会学到这一点!
干杯。
That's actually very good! After your introduction, I was hoping for a mess, I admit.
You did a very good job there, man. Whatever you can improve, you'll learn in due time :). Keep working like that!
I was about to suggest you look up what "abstract data types" are, and how to expose interfaces obscuring implementation, but as I said -- you'll learn that soon enough!
Cheers.
快速浏览一下 Add_Student(...) 函数。看起来像是一个小内存泄漏。如果您愿意,我可以更具体,但我认为您可能需要练习。
Take a quick look at the Add_Student(...) function. Looks like a small memory leak. I can be more specific if you want, but thought you may want the practice.
scanf("%19s", &student_first_name);
scanf("%19s", &student_first_name);
您选择的多个变量名称会使代码不必要地混乱。例如,在
Show_List
中,您有一个名为firstNodeCopy
的内容,它不是任何节点的副本,并且并不总是引用第一个节点。在
Add_Student
中,您进行了很多不同的比较,我什至不确定您真正想要完成什么,但我很确定您所拥有的内容还有待改进。同样,您有一些变量(例如,start
),其名称似乎并不能非常明确地表明它们真正应该做什么/是什么。我建议稍微改变一下结构:创建一个函数compare_students(或类似的东西),它只是处理一个学生与另一个学生的比较,并(例如)告诉你两个学生 A 和 B 是有序的还是无序的。我可能还会添加一个“创建学生”来获取一组输入并从中创建一个学生结构。从那里开始,插入算法看起来像这样:
You choices of a number of variable names make the code unnecessarily confusing. For example, in
Show_List
, you have something namedfirstNodeCopy
that isn't a copy of any node, and doesn't always refer to the first node.In
Add_Student
, you have so many different comparisons I'm not even sure what you're really even trying to accomplish, but I'm pretty sure what you have is open to improvement. Again, you have some variables (e.g.,start
) whose names don't seem to be a very solid indication of what they're really supposed to do/be.I'd advise changing the structure a bit: create a function
compare_students
(or something like that) that just handles comparing one student to another, and (for example) telling you whether two students A and B are in order or out of order. I'd probably also add a "create student" to take a set of inputs and create a student structure from them. From there, the insertion algorithm looks something like:我发现了一些问题
#include
:在此程序中,您需要
、
和>
enum
或#define
而不是在源代码中添加“幻数”,scanf
和检查返回值'\n'
:printf("...\n" )
vsprintf("\n...")
strcmp
s编译,并将警告级别推至 MAX,并尝试获取摆脱所有警告。
Some nitpicks I found
#include
: in this program you need<stdio.h>
,<stdlib.h>
, and<string.h>
enum
or#define
rather than sprinking your source with "magic numbers"scanf
and check return value'\n'
at end of output:printf("...\n")
vsprintf("\n...")
strcmp
sCompile with warning level pushed to the MAX, and try to get rid of all warnings.
您可以将
void Menu()
的原型更改为void Menu(void)
。这样编译器就可以检查函数是否被正确调用。如果在编译时就可以发现错误,那总是好的。You could change the prototype of
void Menu()
tovoid Menu(void)
. This way the compiler can check whether the function is called correctly or not. It is always good if errors can already be found at compile time.