Search code examples
c++strcmp

Why does strcmp returns 0 when called from within a find_if? C++


I have a vector of elements. These elements are structs containing a path and I would like to find an element with a specific path.

I tried using std::find_if, as shown below in the UseFindIf method, but the call to strcmp always returns 0 regardless of whether the const char ptrs are the same or not.

I then tried using a for loop to go through the iterators of the container, as shown in the UseForLoop method, and it worked as expected.

Does anyone know why strcmp behaves like this when called within a find_if?

In the code below calling UseFindIf prints Found and calling UseForLoop prints NotFound

(The int member of the struct is irrelevant)

#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>

using namespace std;

struct MyStruct
{
    string path;
    int aNumber = 9;
};

void UseFindIf(const vector<MyStruct>& container,  const char* _path)
{
    auto itFoundTexture = std::find_if( container.begin(), container.begin(), [&]( const MyStruct& _td ) 
        {
            return strcmp( _td.path.c_str(), _path ) == 0;
        });
        
    cout << (itFoundTexture == container.end() ? "Not Found" : "Found") << endl;
}

void UseForLoop(const vector<MyStruct>& container,  const char* _path)
{
    auto itFoundTexture = container.begin();

    for (; itFoundTexture != container.end(); ++itFoundTexture)
    {
        if (strcmp( itFoundTexture->path.c_str(), _path ) == 0) break;
    }
    
    cout << (itFoundTexture == container.end() ? "Not Found" : "Found") << endl;
}


int main()
{
    vector<MyStruct> container;
    MyStruct data;
    data.path = "../assets/test.jpg";
    data.aNumber = 888;
    container.push_back(data);
    
    UseFindIf(container, "../assets/othertest.jpg");
    UseForLoop(container, "../assets/othertest.jpg");

    return 0;
}

I also tried writing the lambda so it compares strings instead of char pointers, but same result.

void UseFindIf(vector<MyStruct>& container,  const char* _path)
{
    string strTest(_path);
    auto itFoundTexture = std::find_if( container.begin(), container.begin(), [&]( const MyStruct& _td ) 
        {
            return _td.path == strTest;
        });
        
    cout << (itFoundTexture == container.end() ? "Not Found" : "Found") << endl;
}

I can also say that the issue is not related to the lambda, I ran the same lambda outside of the find_if and it behaves as expected.

In case it helps, I am using C++20 in my project in VS. I also tried using https://www.onlinegdb.com/online_c++_compiler and same result.

Thanks in advance!


Solution

  • You have a typo in UseFindIf(). The iterator range you are specifying is [begin..begin) instead of [begin..end), so your lambda will never see any of the vector's elements, and itFoundTexture will always be set to the begin iterator, thus why you always see Found regardless of the actual search result (when the vector is not empty).

    You need to change this:

    std::find_if( container.begin(), container.begin(), ...);
                                               ^
    

    To this instead:

    std::find_if( container.begin(), container.end(), ...);
                                               ^