I've implemented a variant of giorashc s solution, with all the suggested fixes and issues resolved: Its a bit long but it should be fast if everything is inlined: Most of the code is tests which I've left in for completeness.
#include <iostream>
#include <math.h>
char get_kth_digit( int v, int index)
{
  assert(v>0);
  int mask = pow(10,index);
  return '0'+(v % (mask*10))/mask;
}
int count_digits( int v )
{
  assert(v>0);
  int c=0;
  while(v>0)
  {
    ++c;
    v/=10;
  }
  return c;
}
char get_int_index(int v, int index)
{
  if( v==0 ) return '0';
  if( v <  0 )
  {
    if(index==0) { return '-'; }
    return get_int_index(-v,index-1);
  }
  // get_kth_digit counts the wrong way, so we need to reverse the count
  int digits = count_digits(v);
  return get_kth_digit( v, digits-index-1);
}
template<typename X, typename Y>
void compare(const X & v1, const Y & v2, const char * v1t, const char * v2t, uint32_t line, const char * fname )
{
  if(v1!=v2)
  {
    std::cerr<<fname<<":"<<line<<": Equality test failed "<< v1t  << "("<<v1<<") <> " << v2t <<" ("<<v2<<")"<<std::endl;
  }
}
#define test_eq(X,Y) compare(X,Y,#X,#Y,__LINE__,__FILE__)
int main()
{
  test_eq( 1, count_digits(1) );
  test_eq( 1, count_digits(9) );
  test_eq( 2, count_digits(10) );
  test_eq( 2, count_digits(99) );
  test_eq( 3, count_digits(100) );
  test_eq( 3, count_digits(999) );
  test_eq( '1', get_kth_digit(123,2) );
  test_eq( '2', get_kth_digit(123,1) );
  test_eq( '3', get_kth_digit(123,0) );
  test_eq( '0', get_kth_digit(10,0) );
  test_eq( '1', get_kth_digit(10,1) );
  test_eq( '1', get_int_index(123,0) );
  test_eq( '2', get_int_index(123,1) );
  test_eq( '3', get_int_index(123,2) );
  test_eq( '-', get_int_index(-123,0) );
  test_eq( '1', get_int_index(-123,1) );
  test_eq( '2', get_int_index(-123,2) );
  test_eq( '3', get_int_index(-123,3) );
}