Почему часть строки не может быть передана в atoi или stoi?

#c #string #type-conversion #substring

#c #строка #преобразование типов #подстрока

Вопрос:

Я попытался сделать это с некоторыми подстроками, которые все были натуральными числами

 fi = stoi(f[i]) - stoi(s[i]);
se = stoi(s[i]) - stoi(f[i]);
  

где f и s — это 2 строки. Это было решено, когда я присвоил часть строки новой переменной. Я сталкивался с похожими вещами с atoi(str.c_str()). Почему stoi и atoi ведут себя подобным образом?

Комментарии:

1. Что это stoi(f[i]) предполагает сделать?

2. Превратить подстроку в целое число

3. f[i] - ‘0’ значение представлено символом цифры f[i] .

4. Только если значение f[i] находится между символами '0' .. '9' включительно, в противном случае результат будет неопределенным , в зависимости от используемого набора символов.

5. Обратите внимание, что C 17 ввел преобразования более низкого уровня в <charconv> , которые позволили бы вам делать то, что вы хотите.

Ответ №1:

Почему часть строки не может быть передана в atoi или stoi?

Это возможно, но для получения подстроки из std::string вам нужно вызвать std::string::substr() метод. Что-то вроде:

 std::stoi( f.substr( i, 1 ) ); 
  

предполагая, что вы хотите, чтобы длина подстроки составляла 1 символ, начиная с позиции i . std::string::operator[] выдает вам не подстроку, а один символ из этой позиции, т. Е. std::string может выступать в качестве контейнера символов.

Ответ №2:

Если f и s являются string s, то f[i] и s[i] являются одиночными char s. atoi() и std::stoi() не принимают одиночные char s в качестве входных данных. Они просто не предназначены для такой работы.

atoi() принимает const char* в качестве входных данных и ожидает, что это будет указатель на строку в стиле C с нулевым завершением. Итак, чтобы передать ей один char , вам сначала нужно будет создать char[2] массив, например:

 char arr[] = { f[i], '' };
int i = atoi(arr);
  

std::stoi() принимает std::string в качестве входных данных. Чтобы передать ей один символ char , вам сначала нужно создать 1 символ std::string . Однако, std::string не имеет конструктора, который принимает только один char в качестве входных данных, но есть много разных способов, которыми вы можете создать 1-символ std::string , например:

 std::string s(1, f[i]);
int i = std::stoi(s);
  
 std::string s(f, i, 1);
int i = std::stoi(s);
  
 std::string s(amp;f[i], 1);
int i = std::stoi(s);
  
 std::string s(f i, f (i 1)); // if f is a char[]/char*
int i = std::stoi(s);
  
 std::string s(f.begin() i, f.begin() (i 1)); // if f is a std::string
int i = std::stoi(s);
  
 std::string s = f.substr(i, 1); // if f is a std::string
int i = std::stoi(s);
  
 std::string s = { f[i] };
int i = std::stoi(s);
  
 std::string s;
s = f[i]; // std::string has an operator=(char) overload
int i = std::stoi(s);
  
 std::string s;
s.resize(1);;
s[0] = f[i];
int i = std::stoi(s);
  
 std::string s = std::string_view(amp;f[i], 1);
int i = std::stoi(s);
  

При этом, если все char s находятся между '0' .. '9' включительно, то вам не нужно использовать atoi() / std::stoi() для преобразования их в целые числа. Вместо этого просто вычтите '0' из них, например:

 fi = (f[i] - '0') - (s[i] - '0');
se = (s[i] - '0') - (f[i] - '0');
  

Это работает, потому что в ASCII символы '0' .. '9' определяются как последовательные значения 48 .. 57, таким образом, вышесказанное действительно просто делает это:

'0' - '0' = 0 -> 48 - 48 = 0
'1' - '0' = 1 -> 49 - 48 = 1
'2' - '0' = 2 -> 50 - 48 = 2
и так далее…

Комментарии:

1. std::stoi() не ожидает строку в стиле C с нулевым завершением.

2. @Slava внутренне, std::stoi() просто вызывает std::strtol() , который ожидает строку C с нулевым завершением. std:string гарантированно завершается нулем в C 11 и более поздних версиях.