FRR
FRR

Reputation: 99

Sort a 2D character Array using sort() in C++

I have a 2D character array (I don't want to use array of std::string). How can I sort the strings (char*) in ascending order according to the length of the string using std::sort()?

I have tried the following. But it doesn't work.

char names[100][30];

bool comp(const char* a, const char* b){
    return strlen(a)<strlen(b);
}

int main(){
    ...
    //I want to sort the first n strings 
    sort(names,names+n,comp); //n<=100
    ...
}

I have found these errors:

1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3128) : error C2075: '_Val' : array initialization needs curly braces
1>        e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3150) : see reference to function template instantiation 'void std::_Insertion_sort1<_BidIt,bool(__cdecl *)(const char *,const char *),char[30]>(_BidIt,_BidIt,_Pr,_Ty (*))' being compiled
1>        with
1>        [
1>            _BidIt=char (*)[30],
1>            _Pr=bool (__cdecl *)(const char *,const char *),
1>            _Ty=char [30]
1>        ]
1>        e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3270) : see reference to function template instantiation 'void std::_Insertion_sort<_RanIt,bool(__cdecl *)(const char *,const char *)>(_BidIt,_BidIt,_Pr)' being compiled
1>        with
1>        [
1>            _RanIt=char (*)[30],
1>            _BidIt=char (*)[30],
1>            _Pr=bool (__cdecl *)(const char *,const char *)
1>        ]
1>        e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3279) : see reference to function template instantiation 'void std::_Sort<char(*)[30],int,bool(__cdecl *)(const char *,const char *)>(_RanIt,_RanIt,_Diff,_Pr)' being compiled
1>        with
1>        [
1>            _RanIt=char (*)[30],
1>            _Diff=int,
1>            _Pr=bool (__cdecl *)(const char *,const char *)
1>        ]
1>        e:\projects visual studio2008\sample\sample\sorting.cpp(51) : see reference to function template instantiation 'void std::sort<char(*)[30],bool(__cdecl *)(const char *,const char *)>(_RanIt,_RanIt,_Pr)' being compiled
1>        with
1>        [
1>            _RanIt=char (*)[30],
1>            _Pr=bool (__cdecl *)(const char *,const char *)
1>        ]
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3133) : error C2106: '=' : left operand must be l-value
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3140) : error C2106: '=' : left operand must be l-value
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3141) : error C2106: '=' : left operand must be l-value
1>Build log was saved at "file://e:\projects visual studio2008\sample\sample\Debug\BuildLog.htm"
1>sample - 4 error(s), 3 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Upvotes: 4

Views: 1778

Answers (4)

rcgldr
rcgldr

Reputation: 28826

As already mentioned, arrays can't be assigned. Structures can be assigned, so this might be close to what you want. The array of structures might be padded for alignment. In the case of Visual Studio 2015, the array of structures was not padded, so the memory layout was the same as a 2d array.

update - changed to using references for compare parameters and switched to strnlen as suggested by Jarod42.

#include <algorithm>
#include <cstring>

using namespace std;

typedef struct
{
    char name[30];
}name;

name names[4] = { { "12345678" },{ "123" },{ "12345" },{ "12" } };

bool comp(const name &a, const name &b)
{
    return strnlen(a.name,30) < strnlen(b.name,30);
}

int main(){
    sort(names, names+4, comp);
    return 0;
}

Upvotes: 1

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42909

std::sort requires that its iterator type parameter must be:

  • ValueSwappable and RandomAccessIterator.

The type of dereferenced iterator type must meet the requirements of:

  • MoveAssignable and MoveConstructible.

Unfortunately, arrays are not swappable (i.e., you cannot assign one to the other). Consequently, you can't use std::sort with arrays.

What you can do is use std::array<std::array<char, N>, M> in the following manner:

template<std::size_t N, std::size_t M>
void custom_sort(std::array<std::array<char, M>, N> &arrs) {
  std::sort(std::begin(arrs), std::end(arrs), [](auto const &a, auto const &b){ return strnlen(a.data(), M) < strnlen(b.data(), M); });
}

LIVE DEMO

Impovements to code thanks to @Jarod42

Upvotes: 2

Sakib Ahammed
Sakib Ahammed

Reputation: 2480

You can try this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define M 10000

int main()
{
    char names[M][15];
    int n, i;
    scanf("%d", &n);
    for (i = 0; i < n; i++)
        scanf("%s", names[i]);
    qsort(names, n, 15, (int (*)(const void *, const void *))strcmp);

    for(i = 0; i < n; i++)
        printf("%s\n", names[i]);
}

Upvotes: 0

6502
6502

Reputation: 114539

If your data is in

char names[100][30];

then you cannot sort "the pointers" because that data structure has no pointers at all... just 100*30 = 3000 characters one after another. Therefore to do the sorting you will need to actually move around the 100 rows will all their content.

std::sort cannot be used directly because the data structure is an array of arrays, and arrays are in C++ second-class citizens (for example you cannot assign an array to another).

Upvotes: 5

Related Questions