Why is it impossible to pass parameters to the comparator by reference? What do you need to transfer there and what is not needed? How to sort a two-dimensional array using such a function and why does this code not work?

#include <cstdio> #include <algorithm> using namespace std; const int maxN = 100, maxM = 150; int n, m; bool cmp ( int* A1, int* A2 ){ int i = 0; while ( ( i < m ) && ( A1[i] == A2[i] ) ) i++; if ( ( i == m ) || ( A1[i] > A2[i] ) ) return true; return false; } int main(){ int i, j, M[maxN][maxM]; scanf(" %d %d ", &n, &m ); for ( i = 0; i < n; i++ ) for ( j = 0; j < m; j++ ) scanf( "%d", &M[i][j] ); sort ( M, M + n, cmp ); return 0; } 

    2 answers 2

    You could write like this, for example

     #include <iostream> #include <iterator> #include <algorithm> #include <array> #include <functional> int main() { int a[][3] = { { 1, 2, 3 }, { 1, 1, 3 } }; for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::sort( reinterpret_cast<std::array<int, 3> *>( std::begin( a ) ), reinterpret_cast<std::array<int, 3> *>( std::end( a ) ), std::less<>() ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::sort( reinterpret_cast<std::array<int, 3> *>( std::begin( a ) ), reinterpret_cast<std::array<int, 3> *>( std::end( a ) ), std::greater<>() ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; } 

    The output of the program to the console:

     1 2 3 1 1 3 1 1 3 1 2 3 1 2 3 1 1 3 

    As you can see, first the array is sorted in ascending order, and then in descending order, using standard functional objects std::less (it could not be used at all, because operator <would be used instead, declared for the class std::array ) and std::greater .

    The problem is that interpreting a pointer to a one-dimensional array as a pointer to an object std::array and then accessing the elements of the object through this pointer is not entirely correct in C ++, although the program has successfully completed.

    As for arrays, the problem is not that the std::swap function cannot be applied to them, it can be successfully applied to arrays, but that the sorted elements must be MoveConstructible and MoveAssignable , that is, in the appendix to arrays this means that arrays must be assignable or initialized with other arrays. However, for arrays, there is no move assignment operator and no move constructor.

    In the example I showed with std::array this problem does not exist, since this class has an implicitly defined by the compiler relocation assignment operator and a relocation constructor.

    I gave this example so that you could declare an array of objects std::array<int, maxM> . for example

     #include <array> //... std::array<int, maxM> M[maxN]; 

    and then without problems could cause function std::sort .

    Therefore, if you want to sort the two-dimensional array, then you will have to write the sorting function yourself, or use the standard C function qsort , declared in the header file <cstdlib> .

    I will show a simplified version, when the number of compared elements in the array row coincides with the dimension of the array string. In your case, this is not the case; therefore, in the corporate functions you should take into account the number of actually compared elements. These numbers can be included in these functions by calling inside other functions that return a given value of the number of actually compared elements in an array string.

     #include <iostream> #include <cstdlib> const int maxN = 2, maxM = 3; int cmp_ascending( const void *lhs, const void *rhs ) { const int ( *a )[maxM] = reinterpret_cast<const int ( * )[maxM]>( lhs ); const int ( *b )[maxM] = reinterpret_cast<const int ( * )[maxM]>( rhs ); const int *first1 = *a, *last1 = *a + maxM; const int *first2 = *b; while ( first1 != last1 && *first1 == *first2 ) ++first1, ++first2; return first1 == last1 ? 0 : ( *first1 > *first2 ) - ( *first1 < *first2 ); } int cmp_descending( const void *lhs, const void *rhs ) { const int ( *a )[maxM] = reinterpret_cast<const int ( * )[maxM]>( lhs ); const int ( *b )[maxM] = reinterpret_cast<const int ( * )[maxM]>( rhs ); const int *first1 = *a, *last1 = *a + maxM; const int *first2 = *b; while ( first1 != last1 && *first1 == *first2 ) ++first1, ++first2; return first1 == last1 ? 0 : ( *first2 > *first1 ) - ( *first2 < *first1 ); } int main() { int a[][3] = { { 1, 2, 3 }, { 1, 1, 3 } }; for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::qsort( a, maxN, sizeof( *a ), cmp_ascending ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::qsort( a, maxN, sizeof( *a ), cmp_descending ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; } 

    The output to the console will be the same as in the previous program:

     1 2 3 1 1 3 1 1 3 1 2 3 1 2 3 1 1 3 

    You could bypass these difficulties if you dynamically allocated an array of pointers to one-dimensional arrays.

    Otherwise, if you do not want to mess around with arrays, then it is better to use the standard class std::vector<std::vector<int>>

    So you have the following four possibilities.

    The first is to declare an array of objects of the class std::array

     std::array<int, maxM> M[maxN]; 

    In this case, there will be no problems with sorting.

    The second is to declare an array of pointers, and then initialize each array pointer to the address of a dynamically allocated one-dimensional array. for example

     int * M[mxN]; for ( int i = 0; i < maxN; i++ ) M[i] = new int[maxM]; 

    In this case, there will be no problems with std::sort .

    The third is to leave the array declaration as it is in your program, and use the standard C function qsort declared in the <cstdlib> header

    Fourth - use the standard std::vector container to include the following declaration in the program

     std::vector<std::vector<int>> M( maxN, std::vector<int>( maxM ) ); 

      The point is not a comparator, but std::sort cannot sort an array of arrays, since it cannot assign new values ​​to array elements (it is impossible to assign an array to an array).

      Use vector<vector<int>> .

      • The problem of sorting an array has nothing to do with the std :: swap function. Just this function you can successfully apply to arrays. The problem is that arrays are not MoveConstrutibel and MoveAssignable. - Vlad from Moscow
      • @VladfromMoscow ok, corrected - Abyx