John Lexus
John Lexus

Reputation: 3626

How to write function that accepts comparator in C?

I have a struct vector that holds it's data in a double void pointer. The struct looks like this:

typedef struct vector {
    void **data;
    int capacity;
    int size;
} vector;

I am trying to somewhat replicate the std::find function in C++ to find items in the vector that I have. I have done this by creating a function vector_find:

int vector_find(vector* v, void *elem, __compar_fn_t cmp)
{
    for (int i = 0; i < v->size - 1; i++)
    {
        if(cmp(v->data[i], elem) == 0)
        {
            return i;
        }
    }
    return -1;
}

This function is found in my vector.c file. It accepts a comparator function. If it finds the element, it will return its location in the vector.

This is all defined in my vector.c file.

Now I am trying to use this function in one of my programs, in this function:

int cstring_cmp(const void *a, const void *b)
{
    const char *ia = *(const char **)a;
    const char *ib = *(const char **)b;
    printf("%s    %s", ia, ib);
    return strcmp(ia, ib);
}

void
execute(vector* tokens)
{
    if (vector_find(tokens, ";", cstring_cmp) > -1)
    {
        printf("semicolon found");
    }
}

However, when I run this function, I get a segfault with the following error:

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
120 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.

A couple of things I have verified:

  1. I have verified that the error occurs in my execute function. Specifically when I call vector_find.

  2. I have verified that this error comes up whether or not tokens is empty. This is interesting because the for-loop in vector_find should never execute if the vector I pass to vector_find is empty.

  3. I have included in both vector.c and the file I am running.

I have also tried this format:

int vector_find(vector* v, void *elem, int (*cmp) (const void*, const void*))
{
    for (int i = 0; i < v->size; i++)
    {
        if((*cmp) (v->data[i], elem) == 0)
        {
            return i;
        }
    }
    return -1;
}

...and got the same error.

Am I doing this right? Obviously not - where does my error lie?

Upvotes: 2

Views: 82

Answers (2)

dbush
dbush

Reputation: 223739

Your comparison function is expecting that each of its parameters is a char **. However, you call vector_find with a char * being passed as the second parameter which is subsequently passed to cmp. Attempting to use a char * as a char ** invokes undefined behavior as you end up passing to strcmp is actually a char.

You don't show how you populate your vector, but I'm guessing the elements of data are of type char *. That being the case, the comparison function should be expecting a char * instead of a char **.

int cstring_cmp(const void *a, const void *b)
{
    const char *ia = a;
    const char *ib = b;
    printf("%s    %s", ia, ib);
    return strcmp(ia, ib);
}

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

If I'm reading this right, you've written a comparator that pretends a vector is a const char*. It isn't. The subsequent C-string comparison is likely not to hit a would-be null terminator and is going to go out of bounds.

Instead, write a comparator that actually compares vector objects to whatever it is that you want to compare them to.

Upvotes: 0

Related Questions