Bane Bojanić
Bane Bojanić

Reputation: 712

A function searching through an array of structures (C)

This is an address:

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

The goal is to have an address book in the main function, and the user should be able to type in a string, and the program lists out all of the people from the address book whose name or the last name contains the given string. For example, if the address book contains "john" "doe", "jane" "doey" and "george" "johnson", and the user types in "doe", the output is:

 1. john doe [email protected]
 2. jane doey [email protected]

This part of the main function should use a function

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

which returns the index of the first found address, and -1 in case no address has been found.

Here's my try:

In the snippet from my main function (there 's no need to post input stuff here):

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

And here's the search function:

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

However, this program gets stuck in an infinite loop in pretty much any case when there is more than one member in the address book. I'm suspecting that in the while loop the search doesn't go on from the previously found member, but rather it starts from the begin each time, therefore it keeps finding the same, firstly found member each time.

Upvotes: 2

Views: 3609

Answers (2)

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53006

You have a few problems to mention

  1. You call search() twice in your main loop which is absolutely unnecessary, you should call it once and store it's return value.

  2. Your member pointer, never points after the first match, so the first match will always be found, leading to an infinite loop.

  3. You increase the member pointer and still pass number_of_elements to the search function. When you increase the member pointer the number of elements left to the right of it's resulting position is decreased by the same number that you increase member.

  4. This expression is not giving the value you think

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

    because you are computing the distaince between the two pointers i and array and then dividing it by sizeof(struct Address) which is 110, and as another answer mentioned, the value is automatically scaled, so

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

    to see what I mean you may try to print this values

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

    Note: if your OS is 64bit, change the format specifier to "%ld".

This is the code that will do what you need

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

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

in this approach, the member pointer is increased inside the search() function to point to the found element, a counter is added to reflect how much was advanced.

After the search() function returns, member should be increased by 1 again to point to the next element, and number_of_elements should be decreased by the number of elements advanced in the search function + 1 for the found element.

Also, keep a variable that you update on each iteration that gives you the actual index of the element in the array.

Upvotes: 1

WhozCraig
WhozCraig

Reputation: 66204

Your search never actually returns -1, and your invoke of that search doesn't thusly have an exit condition. Further, you should be adjust each starting point of the next search to be one slot beyond the last discovery point.

I'm nearly certain this is what you're trying to do. I've not tested this (have no data to do so nor any info on the invocation of this functionality), but I hope the point is obvious:

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

Hope it helps. Best of luck.

Upvotes: 1

Related Questions