2

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.

16
  • 1
    Why invoke search twice ?? Once, saving the result, testing for -1, and if not, use the result as an offset rather than invoking the same function with the same parameters again ? And you don't need the division calculation of index in search. Pointer math will do that for you. index = (i - array); should be sufficient to get the correct index. Commented Jan 10, 2015 at 12:53
  • Hm, how would I get the index without this division? And I know things could be optimised a bit, but primarily I need to make it work and figure out why does it get into an infinite loope. Commented Jan 10, 2015 at 12:57
  • This is strangely written code. Why not just use an integer index i which iterates from 0 to the length of the array and reference, array[i].name, etc? As far as the infinite loop, how is size_of_the_addressbook computed before being passed to the function? Commented Jan 10, 2015 at 12:58
  • Again, pointer arithmetic. Its done twice in this code, both wrong. No sizeof division is needed for what you're doing. Commented Jan 10, 2015 at 12:58
  • 1
    Right. So your loop inside the function can still iterate int i from 0 to number_of_elements-1 referencing array[i]. It would be much cleaner, and your loop would at least properly terminate, leaving you to address other issues. Commented Jan 10, 2015 at 13:11

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

This line: *end = array + size_of_the_addressbook; array + size_of_the addressbook might go beyond the addressbook array? edit: nevermind, I saw the adjustment in the second function.
Unfortunately, your function prints out an infinite number of lines containing the firstly found member, exactly like my function did...
@BaneBojanić yeah, I just realized that. base was not being adjusted correctly. It should work now. That'll teach me to post untested code.
Thanks a lot. I guess I should've posted the whole code, but it was difficult because I'd have to translate all the variables to English to make it readable...
1

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.

5 Comments

If i compare it with size_of_the_addressbook -1, it still gets stuck inside an infinite loop.
@BaneBojanić How can you tell that it's an infinite loop? did you use a debugger?
Say that I have two members with the same last name and different first names. If I search for the last name (or a part of it) the program prints out infinite lines of i. first member's name first member's last name, with i going from 1 to infinity.
@BaneBojanić why are you calling search twice?
trouble? what trouble?, I was having a lot of fun with your code... :) I hope it hepls you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.