4

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 ==========
8
  • Doesn't work isn't an error destription. That said, use std::vector or std::array and std::string, it would work then. Commented Oct 22, 2015 at 6:23
  • @UlrichEckhardt Unfortunately there isn't an equivalent of a 2D array using either of those. Of course one can always write a 2D array class with a single array/vector/whatever as storage. Commented Oct 22, 2015 at 6:27
  • 1
    FRR: You don't even mention an error message let alone provide a minimal example. @juanchopanza: That's just a 1-D array of fixed-length strings, if I understand it correctly given the limited info here. Commented Oct 22, 2015 at 6:29
  • 2
    sort will try to swap a and b using the result of comp. Not going to work well with char[30]. Commented Oct 22, 2015 at 6:35
  • 1
    The elements of names are not pointers (char*), they are arrays (char[30]). char* names[100] would work. Commented Oct 22, 2015 at 6:43

4 Answers 4

5

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).

Sign up to request clarification or add additional context in comments.

Comments

2

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

3 Comments

strnlen(a.data(), M) < strnlen(b.data(), M) to avoid possible out of bound accesses.
And missing reference to avoid unneeded copy.
@Jarod42 Thanks I wasn't even aware of strnlen :)
1

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;
}

Comments

0

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]);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.