【问题标题】:A function searching through an array of structures (C)搜索结构数组的函数 (C)
【发布时间】:2015-03-08 16:58:25
【问题描述】:

这是一个地址:

struct Adress {
    char name[31], lastname[31], email[48];
};

目标是在 main 函数中有一个通讯录,用户应该能够输入一个字符串,程序会列出通讯录中姓名或姓氏包含给定值的所有人细绳。 例如,如果通讯录中包含“john”、“doe”、“jane”、“doey”和“george”“johnson”,并且用户输入“doe”,则输出为:

 1. john doe johndoe@email.com
 2. jane doey janedoey@email.com

这部分主函数应该使用一个函数

int search(struct Adress array[], int size_of_the_addressbook, char* string_to_search)

返回第一个找到的地址的索引,如果没有找到地址,则返回-1。

这是我的尝试:

在我的主要功能的 sn-p 中(这里不需要发布输入内容):

    struct Adress adressbook[1000], *member;
    int i = 0;
    member = adressbook;

    if (search(member, number_of_elements, string_to_seach)) == -1)
                printf("No person found.\n");

    else while((search(member, number_of_elements, string_to_seach)) != -1)
            {
                member = adressbook + search(member, number_of_elements, string_to_seach);
                ++i;


                printf("%d. %s %s - %s\n", i, (*member).name, (*member).lastname, (*member).email);
                ++member;
            }

这里是搜索功能:

int search(struct Adress array[], int size_of_the_addressbook, char* string_to_search)
{
    int j, index;
    struct Adress *i;
    i = array;

    while (strstr((*i).name, string_to_search) == 0 && strstr((*i).lastname, string_to_search) == 0)
    {
        index = ((i - array)/(sizeof (struct Adress)));
        if (index == size_of_the_addressbook)   return -1;
        ++i;
    }
    index = ((i - array)/(sizeof (struct Adresa)));
    return index;
}

但是,当通讯簿中有多个成员时,几乎任何情况下,此程序都会陷入无限循环。我怀疑在 while 循环中,搜索不是从先前找到的成员开始,而是每次都从头开始,因此每次都会找到相同的第一个找到的成员。

【问题讨论】:

  • 为什么调用搜索两次??一次,保存结果,测试 -1,如果不是,将结果用作偏移量,而不是调用具有相同参数的相同函数 again ?而且你不需要indexsearch中的除法计算。指针数学将为您做到这一点。 index = (i - array); 应该足以获得正确的索引。
  • 嗯,如果没有这个除法,我将如何获得索引?而且我知道事情可以进行一些优化,但首先我需要让它工作并弄清楚为什么它会进入无限循环。
  • 这是一段奇怪的代码。为什么不直接使用整数索引i,它从0 迭代到数组和引用的长度,array[i].name 等?至于无限循环,size_of_the_addressbook 在传递给函数之前是如何计算的?
  • 再次,指针算法。它在这段代码中做了两次,都是错误的。您正在做的事情不需要 sizeof 除法。
  • 对。所以你在函数中的循环仍然可以将int i0迭代到number_of_elements-1引用array[i]。它会更干净,您的循环至少会正确终止,让您解决其他问题。

标签: c arrays search


【解决方案1】:

你有几个问题要提

  1. 您在主循环中调用了两次search(),这是绝对没有必要的,您应该调用一次并存储它的返回值。

  2. 你的member指针,在第一个匹配之后永远不会指向,所以总是会找到第一个匹配, 导致无限循环。

  3. 您增加了member 指针,但仍将number_of_elements 传递给搜索函数。当您增加member 指针时,其结果位置左侧的元素数量会减少与增加member 相同的数量。

  4. 这个表达式没有给出你认为的值

    ((i - array)/(sizeof (struct Adress)));
    

    因为您正在计算两个指针 iarray 之间的距离,然后将其除以 sizeof(struct Address)110,并且作为另一个答案提到,该值会自动缩放,所以

    ((i - array)/(sizeof (struct Adress))); -> i - array;
    

    要了解我的意思,您可以尝试打印这些值

    printf("\t%d\n", ((void*)member - (void*)adressbook));
    printf("\t%d\n", ((void*)member - (void*)adressbook) / sizeof(*member));
    printf("\t%d\n", member - adressbook);
    

    注意:如果您的操作系统是 64 位,请将格式说明符更改为 "%ld"

这就是你需要的代码

int search(struct Adress **array, int size_of_the_addressbook, char* string_to_search)
{
    int            index;
    struct Adress *pointer;

    if ((size_of_the_addressbook == 0) || (array == NULL) || (*array == NULL))
        return -1;

    pointer = *array;
    index   = 0;
    while (strstr(pointer->name, string_to_search) == 0 && 
               strstr(pointer->lastname, string_to_search) == 0)
    {
        /* check that we are not at the end of the array. */
        if (++index == size_of_the_addressbook)
            return -1;
        /* not found yet, increment both arrays */
        (*array)++;

        pointer = *array;
    }

    return index;
}

main()

int index;
int foundIndex;

index = 1;
while ((foundIndex = search(&member, number_of_elements, string_to_seach)) != -1)
{
    printf("%d. %s %s - %s\n", index, member->name, member->lastname, member->email);

    index              += 1 + foundIndex;
    number_of_elements -= 1 + foundIndex;

    ++member;
}

在这种方法中,member 指针在 search() 函数内增加以指向找到的元素,并添加一个计数器以反映前进了多少。

search() 函数返回后,member 应再次增加 1 以指向下一个元素,number_of_elements 应减少搜索函数中前进的元素数量 + 1 找到的元素。

另外,保留一个您在每次迭代时更新的变量,它会为您提供数组中元素的实际 index

【讨论】:

  • 如果我将它与 size_of_the_addressbook -1 进行比较,它仍然会陷入无限循环。
  • @BaneBojanić 你怎么知道这是一个无限循环?你用过调试器吗?
  • 假设我有两个姓氏相同但名字不同的成员。如果我搜索姓氏(或其中的一部分),程序会打印出无限行的 i。第一个成员的名字第一个成员的姓氏,i 从 1 到无穷大。
  • @BaneBojanić 为什么要调用两次搜索?
  • 非常感谢您的麻烦。 :)
【解决方案2】:

您的搜索实际上从未返回 -1,因此您对该搜索的调用没有退出条件。此外,您应该将下一次搜索的每个起点调整为最后一个发现点的一个位置。

我几乎可以肯定这就是您正在尝试做的事情。我没有对此进行测试(没有数据可以这样做,也没有关于调用此功能的任何信息),但我希望这一点很明显:

int search(const struct Adress array[],
           int size_of_the_addressbook,
           const char* string_to_search)
{
    const struct Adress *end = array + size_of_the_addressbook;
    const struct Adress *i = array;

    for (; i != end; ++i)
    {
        if (strstr(i->name, string_to_search) != NULL ||
            strstr(i->lastname, string_to_search) != NULL)
            break;
    }

    return i == end ? -1 : (int)(i - array);
}

void do_search(const struct Adress *array,
               int number_of_elements,
               const char *string_to_search)
{
    int i = search(array, number_of_elements, string_to_search), base=0;
    if (i == -1)
    {
        printf("No person found.\n");
        return;
    }

    while (i != -1)
    {
        base += i;
        printf("%d. %s %s - %s\n", base,
               array[base].name,
               array[base].lastname,
               array[base].email);

        base += 1;

        // note adjustment of starting point using pointer arithmetic.
        i = search(array + base,
                   number_of_elements - base,
                   string_to_search);
    }
}

希望对您有所帮助。祝你好运。

【讨论】:

  • 这一行:*end = array + size_of_the_addressbook; array + size_of_the 地址簿可能会超出地址簿数组?编辑:没关系,我在第二个函数中看到了调整。
  • 不幸的是,你的函数打印出无数行包含第一个找到的成员,就像我的函数一样......
  • @BaneBojanić 是的,我刚刚意识到这一点。 base 未正确调整。它现在应该可以工作了。这会教我发布未经测试的代码。
  • 非常感谢。我想我应该发布整个代码,但这很困难,因为我必须将所有变量翻译成英文才能使其可读......
猜你喜欢
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
相关资源
最近更新 更多