我正在尝试完成我的代码,但这个让我难过。我想使用字符串在链表中找到一个元素。问题是,无论我如何更改代码,我都只能找到第一个元素。
int findpatron(struct Library* lib1, struct Patron **p_ptr){
int i;
char f_name[32], l_name[32];
struct Patron_node *currNode = lib1->patrons.node, *prevNode = NULL;
while(currNode != NULL){
printf("Enter the first name of patron: \n");
scanf("%s", f_name);
printf("Enter the last name of patron: \n");
scanf("%s", l_name);
if ((strcmp(currNode->patron->name.first, f_name) == 0) &&
(strcmp(currNode->patron->name.last, l_name) == 0)){
//prevNode = currNode;
*p_ptr = currNode->patron;
break;
}
currNode = currNode->next;
}
return 0;
}
答案 0 :(得分:3)
你的代码似乎在循环的每次迭代中提示赞助名称,这是组织事物的一种不寻常的方式。它可能应该提示循环外的名称。您还应该错误地检查对scanf()
的调用:
if (scanf("%.31s", f_name) != 1)
...break...or otherwise handle I/O problem...
我们可能需要了解如何在库中创建顾客列表。可能是您每次都将名称存储在同一个空间中,或类似的东西。
你的功能总是返回0;没有必要这样说。它不应该返回任何值(void
),因此您不必检查它返回的内容,或者您应该为找到的patron返回struct Patron *
,如果有,则返回NULL(0)是没有匹配的赞助人。
你的结构在我看来意外地深深地嵌套了。这段代码编译,但我没有花费精力填充列表。然而,提供5个结构比我期望的深2或3级。这无疑使你的生活变得复杂。
#include <stdio.h>
#include <string.h>
struct Name
{
char first[32];
char last[32];
};
struct Patron
{
struct Name name;
};
struct Patron_node
{
struct Patron *patron;
struct Patron_node *next;
};
struct Patron_list
{
struct Patron_node *node;
};
struct Library
{
struct Patron_list patrons;
};
int findpatron(struct Library* lib1, struct Patron **p_ptr)
{
char f_name[32], l_name[32];
struct Patron_node *currNode = lib1->patrons.node;
printf("Enter the first name of patron: \n");
if (scanf("%.31s", f_name) != 1)
return -1;
printf("Enter the last name of patron: \n");
if (scanf("%.31s", l_name) != 1)
return -1;
while (currNode != NULL)
{
if (strcmp(currNode->patron->name.first, f_name) == 0 &&
strcmp(currNode->patron->name.last, l_name) == 0)
{
*p_ptr = currNode->patron;
break;
}
currNode = currNode->next;
}
return 0;
}
我注意到我必须发明两个结构名称,因为它们没有显示在源代码中。在某些时候,您应该查找Law of Demeter并找出如何避免在代码中如此肆无忌惮地违反它。
例如:
int name_cmp_by_first(const struct Name *n1, const struct Name *n2)
{
int rc = strcmp(n1->first, n2->first);
if (rc == 0)
rc = strcmp(n1->last, n2->last);
return rc;
}
出于目的,您是先将名字首先与姓氏进行比较并不重要。通常,如果要对数据进行排序(例如),则需要知道对它们进行排序的方式。我正在使用您使用的区分大小写的搜索;再次,您可能想要考虑使用不区分大小写的搜索。如图所示,当你的比较很好地分离和隔离时,你可以更容易地做到这一点。
int prompt_for_name(const char *prompt, char *name)
{
printf("%s", prompt);
if (scanf("%.31s", name) == 1)
return 0;
return -1;
}
int name_read(struct Name *name)
{
if (prompt_for_name("first", name->first) == 0 &&
prompt_for_name("last", name->last) == 0)
return 0;
return -1;
}
请注意,这可以避免重复代码。 Kernighan和Plauger在他们的书'The Elements of Programming Style':
中巧妙地总结了这一点然后在'find_patron()`函数中:
struct Name to_be_found;
if (name_read(&to_be_found) != 0)
return -1; // Error return from function
while ...
if (name_cmp_by_first(&name_to_be_found, currNode->patron->name) == 0)
...found the patron...
这更好;不完全清洁,但更好。一个更现实的功能将采用要找到的顾客的名字,并将在列表中搜索该名称;您不要混合I / O操作,例如使用搜索操作读取顾客名称。这混合了两种非常不同的操作。