10
#include <cinttypes>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
uint64_t descendingOrder(uint64_t a)
{
   string str = to_string(a);
   sort(str.begin(),str.end(),[](unsigned char a , unsigned char b) { return a>b;}); 

   cout<<"sorted string:" <<str<<endl;
   cout<<"value        :"<<strtol(str.c_str(),nullptr,10)<<endl;
   return strtol(str.c_str(),nullptr,10);
}

int main()
{
  descendingOrder(9223372036854775807L);
}

sorted string:9887777655433322200
value        :9223372036854775807

Why are the sorted string: and value: are different? It seems like value: took the original string somehow even after sorting. Where is the mistake? Is it UB?

Code: Online code

Sreeraj Chundayil
  • 5,548
  • 3
  • 29
  • 68
  • 2
    Use [`std::stoull(str)`](https://en.cppreference.com/w/cpp/string/basic_string/stoul) for **unsigned** long long instead. The `strtol` (and `std::stol` in C++) is for **signed** longs. – heap underrun Jun 22 '21 at 10:12
  • 1
    OT: Use `char` instead of `unsigned char` as `std::string` uses `char`. – Simon Kraemer Jun 22 '21 at 11:17

1 Answers1

12

9887777655433322200 is out of range for a long on your architecture.

That's why errno gets set to ERANGE and LONG_MAX (which happens to be your input) is returned. Note that an implementation may also use LLONG_MIN or LLONG_MIN or even LONG_MIN. You need to check errno in order to know whether the conversion with strtol worked.

If you used std::stol you would have ended up with an std::out_of_range exception instead. Whether you want to use exceptions is up to you, but meanwhile, use either std::strtoull for unsigned long long (and check errno) or use std::stoull (and keep possible exceptions in mind).

See [string.conversions] in the C++ standard or the links above to cppreference.com for more information.

Zeta
  • 103,620
  • 13
  • 194
  • 236