如何在链表中查找特定元素

时间:2011-11-04 04:07:20

标签: c

我正在尝试完成我的代码,但这个让我难过。我想使用字符串在链表中找到一个元素。问题是,无论我如何更改代码,我都只能找到第一个元素。

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;
}

1 个答案:

答案 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操作,例如使用搜索操作读取顾客名称。这混合了两种非常不同的操作。