0

I was reading about string and function pointer in C++. There I found a problem sort array of string based on first character value. And here is my code solution.

#include<bits/stdc++.h>
using namespace std;

bool compare1(const void *a, const void  *b)
{
    string c = *(string *)a;
    string d = *(string *)b;
    return c[0]<d[0];
}

int main()
{

    string str[3];
    int i;
    
    for(i=0;i<3;i++)
    {
        cout<<"Enter "<<i+1<<" string";
        cin>>str[i];
    }
    
    cout<<"Before sort"<<endl;
    for(i=0;i<3;i++)                               
    {
        cout<<str[i]<<" ";
    }
    
    cout<<endl;
    
    sort(str.begin(),str.end(),compare1);
    
    cout<<"After sort"<<endl;
    for(i=0;i<3;i++)
    {
        cout<<str[i]<<" ";
    }
    return 0;
}

But I am getting compile time error: [Error] request for member 'begin' in 'str', which is of non-class type 'std::string [3] {aka std::basic_string [3]}'

How to fix this issue?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • It looks like you're confusing the C library's `qsort` with the C++ library's `std::sort`. – molbdnilo Sep 01 '21 at 08:35
  • Unrelated to your problem but you can use a lambda to simplify your code: `std::sort(std::begin(str), std::end(str), [](const std::string& s1, const std::string& s2) { return s1[0] < s2[0]; });` – Botje Sep 01 '21 at 08:35
  • 1
    It looks almost like you're learning programming and C++ from a so-called "competition" or "online judge" site. Don't do that, that's not what they're for. Get [some good books](https://stackoverflow.com/a/388282/440558) to read, and take some classes. You need to do that because you have multiple basic errors in your code. – Some programmer dude Sep 01 '21 at 08:36
  • 1
    you shouldn't use `void*`, especially when the method can only work correctly when `string*`s are passed (though you dont need pointers in the first place) – 463035818_is_not_an_ai Sep 01 '21 at 08:39
  • Aside from the actual answers, you should make sure that your comparison function also checks whether the strings actually have a first element, if you don't want to have a segmentation fault in wait. – Aziuth Sep 01 '21 at 09:05
  • @Someprogrammerdude What are some other basic error can u mentioned them? – Hash include Sep 01 '21 at 13:13
  • @463035818_is_not_a_number But we can type-cast it to string if we are using void * . – Hash include Sep 01 '21 at 13:36
  • @Hashinclude but why would you? The function could be `bool compare1(const string *a, const string *b)`. Your function can be called with pointers to anything but has undefined behavior for most of them – 463035818_is_not_an_ai Sep 01 '21 at 14:21

3 Answers3

2

Two issues:

  1. str is a raw array and doesn't have member function named begin and end. You can use std::begin and std::end instead.

  2. std::sort passes the elements for comparing; compare1 should accept std::strings instead of pointers.

E.g.

bool compare1(const string& c, const string& d)
{
    // for empty strings
    if (c.length() == 0 || d.length() == 0)
        return c.length() < d.length();

    return c[0] < d[0];
}

then

sort(std::begin(str), std::end(str), compare1);

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I propose that you add something that catches whether the strings are of length zero in the comparator. Wouldn't want there to be a segmentation fault in wait. – Aziuth Sep 01 '21 at 09:07
  • 1
    @Aziuth Nice idea. – songyuanyao Sep 01 '21 at 09:19
  • @Hashinclude It's just how [`std::sort`](https://en.cppreference.com/w/cpp/algorithm/sort) works, you have to follow its rules. *The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them.​* – songyuanyao Sep 01 '21 at 13:55
  • Okay thanks I got confused it with qsort() in C language where we can use const void* inside comparator and then typecast it to desired data type. – Hash include Sep 01 '21 at 14:05
  • @Hashinclude C and C++ are quite different. In most cases you won't use raw pointers (and arrays) in C++. – songyuanyao Sep 01 '21 at 14:09
1

Standard C++ arrays don't have a begin member.

Either use the function-style overloads:

sort(std::begin(str), std::end(str), compare1);

or use a std::vector<std::string> str instead.

or use std::array<std::string, 3>, which is a fixed size but does support the begin member.

Botje
  • 26,269
  • 3
  • 31
  • 41
1

I suppose that string is the name of the standard class std::string.

You declared an array of three objects of the type string

string str[3];

Arrays are not classes. So they do not have member functions including begin and end.

Thus this statement

sort(str.begin(),str.end(),compare1);

is incorrect.

There are general functions std::begin and std::end declared in the header that could be used for example like

#include <iterator>

//...

sort( std::begin( str ), std::end( str ), compare1 );

Or without these functions you could write

sort( str, str + 3, compare1 );

On the other hand, the function compare1 is incorrect. The function sort passes to the comparison function two objects of the type std::string or references to such object.

It must be declared and defined at least the following way

bool compare1( const std::string &s1, const std::string &s2 )
{
    return s1[0] < s2[0];
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335