Ваши теги и заголовок говорят, что вы хотите найти решение на C, но ваш вопрос говорит на C или C ++. Какой вы хотите?
In silico
1
@Yann, прости за эту путаницу. Я предпочитаю C.
user618677
1
Это работает, но это не рекомендуемый способ, потому что нет способа обрабатывать ошибки. Никогда не используйте это в рабочем коде, если вы не можете доверять вводу 100%.
Уве Geuder
1
Определите «лучше» и четко укажите, почему вам нужен другой способ.
Маркиз Лорн
3
@EJP Просто чтобы улучшить себя.
user618677
Ответы:
185
Есть strtolчто лучше ИМО. Также я полюбилstrtonum , так что используйте его, если он у вас есть (но помните, что он не переносимый):
что мне нужно включить для strtonum? Я продолжаю получать неявное объявление о предупреждении
jsj
@ trideceth12 В системах, где он доступен, он должен быть объявлен в #<stdlib.h>. Тем не менее, вы можете использовать стандартную strtoumaxальтернативу.
cnicutar
4
Этот ответ не кажется короче, чем первый код спрашивающего.
Azurespot
11
@NoniA. Краткость всегда хороша, но не за счет правильности.
cnicutar
6
Не столько неправильно, сколько небезопасно. atoi () работает, если ввод действителен. Но что, если вы делаете atoi ("кошка")? strtol () имеет определенное поведение, если значение не может быть представлено как long, atoi () - нет.
Даниэль Б.
27
Надежное strtolрешение на основе C89
С участием:
нет неопределенного поведения (как можно было бы иметь с atoiсемьей)
более строгое определение целого, чем strtol(например, без начальных пробелов и конечных символов мусора)
классификация случаев ошибки (например, для предоставления пользователям полезных сообщений об ошибках)
"тестовый набор"
#include<assert.h>#include<ctype.h>#include<errno.h>#include<limits.h>#include<stdio.h>#include<stdlib.h>typedefenum{
STR2INT_SUCCESS,
STR2INT_OVERFLOW,
STR2INT_UNDERFLOW,
STR2INT_INCONVERTIBLE
} str2int_errno;/* Convert string s to int out.
*
* @param[out] out The converted int. Cannot be NULL.
*
* @param[in] s Input string to be converted.
*
* The format is the same as strtol,
* except that the following are inconvertible:
*
* - empty string
* - leading whitespace
* - any trailing characters that are not part of the number
*
* Cannot be NULL.
*
* @param[in] base Base to interpret string in. Same range as strtol (2 to 36).
*
* @return Indicates if the operation succeeded, or why it failed.
*/
str2int_errno str2int(int*out,char*s,int base){char*end;if(s[0]=='\0'|| isspace(s[0]))return STR2INT_INCONVERTIBLE;
errno =0;long l = strtol(s,&end, base);/* Both checks are needed because INT_MAX == LONG_MAX is possible. */if(l > INT_MAX ||(errno == ERANGE && l == LONG_MAX))return STR2INT_OVERFLOW;if(l < INT_MIN ||(errno == ERANGE && l == LONG_MIN))return STR2INT_UNDERFLOW;if(*end !='\0')return STR2INT_INCONVERTIBLE;*out = l;return STR2INT_SUCCESS;}int main(void){int i;/* Lazy to calculate this size properly. */char s[256];/* Simple case. */
assert(str2int(&i,"11",10)== STR2INT_SUCCESS);
assert(i ==11);/* Negative number . */
assert(str2int(&i,"-11",10)== STR2INT_SUCCESS);
assert(i ==-11);/* Different base. */
assert(str2int(&i,"11",16)== STR2INT_SUCCESS);
assert(i ==17);/* 0 */
assert(str2int(&i,"0",10)== STR2INT_SUCCESS);
assert(i ==0);/* INT_MAX. */
sprintf(s,"%d", INT_MAX);
assert(str2int(&i, s,10)== STR2INT_SUCCESS);
assert(i == INT_MAX);/* INT_MIN. */
sprintf(s,"%d", INT_MIN);
assert(str2int(&i, s,10)== STR2INT_SUCCESS);
assert(i == INT_MIN);/* Leading and trailing space. */
assert(str2int(&i," 1",10)== STR2INT_INCONVERTIBLE);
assert(str2int(&i,"1 ",10)== STR2INT_INCONVERTIBLE);/* Trash characters. */
assert(str2int(&i,"a10",10)== STR2INT_INCONVERTIBLE);
assert(str2int(&i,"10a",10)== STR2INT_INCONVERTIBLE);/* int overflow.
*
* `if` needed to avoid undefined behaviour
* on `INT_MAX + 1` if INT_MAX == LONG_MAX.
*/if(INT_MAX < LONG_MAX){
sprintf(s,"%ld",(longint)INT_MAX +1L);
assert(str2int(&i, s,10)== STR2INT_OVERFLOW);}/* int underflow */if(LONG_MIN < INT_MIN){
sprintf(s,"%ld",(longint)INT_MIN -1L);
assert(str2int(&i, s,10)== STR2INT_UNDERFLOW);}/* long overflow */
sprintf(s,"%ld0", LONG_MAX);
assert(str2int(&i, s,10)== STR2INT_OVERFLOW);/* long underflow */
sprintf(s,"%ld0", LONG_MIN);
assert(str2int(&i, s,10)== STR2INT_UNDERFLOW);return EXIT_SUCCESS;}
Хороший крепкий str2int(). Педантичный: использовать isspace((unsigned char) s[0]).
chux - Восстановить Монику
@ chux спасибо! Можете ли вы объяснить немного больше, почему (unsigned char)актеры могут иметь значение?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Компилятор IAR C предупреждает об этом l > INT_MAXи l < INT_MINявляется бессмысленным целочисленным сравнением, поскольку любой результат всегда ложен. Что произойдет, если я изменю их l >= INT_MAXи l <= INT_MINуберу предупреждения? В ARM C long и int - это 32-разрядные подписанные базовые типы данных в ARM C и C ++
например,
@ecle, изменяющий код для получения l >= INT_MAXнеправильной функциональности: пример, возвращающийся STR2INT_OVERFLOWс вводом "32767"и 16-битным int. Используйте условную компиляцию. Пример .
chux - Восстановить Монику
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;было бы лучше, if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}чтобы вызывающий код , чтобы использовать errnoна intвне диапазона. То же самое для if (l < INT_MIN....
chux - Восстановить Монику
24
Не используйте функции из ato...группы. Они сломаны и практически бесполезны. Было бы лучше использовать умеренно лучшее решение sscanf, хотя оно и не идеально.
Для преобразования строки в целое число strto...должны использоваться функции из группы. В вашем конкретном случае это будет strtolфункция.
sscanfна самом деле имеет неопределенное поведение, если он пытается преобразовать число вне диапазона его типа (например, sscanf("999999999999999999999", "%d", &n)).
Кит Томпсон
1
@ Кит Томпсон: Это именно то, что я имею в виду. atoiне обеспечивает значимой обратной связи об успехе / ошибке и имеет неопределенное поведение при переполнении. sscanfобеспечивает обратную связь об успехе / неудаче (возвращаемое значение, что делает его «умеренно лучше»), но при переполнении все еще имеет неопределенное поведение Только strtolжизнеспособное решение.
AnT
1
Согласовано; Я просто хотел подчеркнуть потенциально фатальную проблему с sscanf. (Хотя, признаюсь, я иногда использую atoi, обычно для программ, которые, как я ожидаю, не выживут более 10 минут, прежде чем я удалю источник.)
Кит Томпсон,
5
Вы можете написать немного atoi () для удовольствия:
int my_getnbr(char*str){int result;int puiss;
result =0;
puiss =1;while(('-'==(*str))||((*str)=='+')){if(*str =='-')
puiss = puiss *-1;
str++;}while((*str >='0')&&(*str <='9')){
result =(result *10)+((*str)-'0');
str++;}return(result * puiss);}
Вы также можете сделать его рекурсивным, который может быть старым в 3 строки =)
Большое спасибо .. Но не могли бы вы сказать мне, как работает приведенный ниже код? code((* str) - '0')code
user618677
персонаж имеет значение ascii. Если вы используете uner linux, введите в командной строке man ascii или перейдите по адресу : table-ascii.com . Вы увидите, что символ '0' = 68 (я думаю) для int. Таким образом, чтобы получить число «9» (это «0» + 9), вы получите 9 = «9» - «0». Ты понял?
jDourlens
1
1) Код позволяет "----1" 2) Имеет неопределенное поведение с intпереполнением, когда результат должен быть INT_MIN. Рассмотримmy_getnbr("-2147483648")
Chux - Восстановить Монику
Спасибо за точность, это было только для того, чтобы показать маленький пример. Как говорится, для развлечения и учебы. Вы должны обязательно использовать стандартную библиотеку lib для таких задач. Быстрее и безопаснее!
JDourlens
2
Просто хотел поделиться решением для unsigned long aswell.
unsignedlongToUInt(char* str){unsignedlong mult =1;unsignedlong re =0;int len = strlen(str);for(int i = len -1; i >=0; i--){
re = re +((int)str[i]-48)*mult;
mult = mult*10;}return re;}
Не обрабатывает переполнение. Также параметр должен быть const char *.
Роланд Иллиг
2
Плюс, что это 48значит? Вы предполагаете, что это значение того, '0'где будет выполняться код? Пожалуйста, не навязывайте миру такие широкие предположения!
Тоби Спейт
@TobySpeight Да, я предполагаю, что 48 представляют «0» в таблице ascii.
Джейкоб
3
Не весь мир является ASCII - просто используйте, '0'как вы должны.
Тоби Спейт
вместо этого рекомендуется использовать функцию strtoul .
быстрый час
1
int atoi(constchar* str){int num =0;int i =0;bool isNegetive =false;if(str[i]=='-'){
isNegetive =true;
i++;}while(str[i]&&(str[i]>='0'&& str[i]<='9')){
num = num *10+(str[i]-'0');
i++;}if(isNegetive) num =-1* num;return num;}
#include<stdio.h>#include<string.h>#include<math.h>int my_atoi(constchar* snum){int idx, strIdx =0, accum =0, numIsNeg =0;constunsignedint NUMLEN =(int)strlen(snum);/* Check if negative number and flag it. */if(snum[0]==0x2d)
numIsNeg =1;for(idx = NUMLEN -1; idx >=0; idx--){/* Only process numbers from 0 through 9. */if(snum[strIdx]>=0x30&& snum[strIdx]<=0x39)
accum +=(snum[strIdx]-0x30)* pow(10, idx);
strIdx++;}/* Check flag to see if originally passed -ve number and convert result if so. */if(!numIsNeg)return accum;elsereturn accum *-1;}int main(){/* Tests... */
printf("Returned number is: %d\n", my_atoi("34574"));
printf("Returned number is: %d\n", my_atoi("-23"));return0;}
Это будет делать то, что вы хотите без беспорядка.
Но почему? Это не проверяет переполнение и просто игнорирует значения мусора. Нет причин не использовать strto...семейство функций. Они портативны и значительно лучше.
Чад
1
Странно использовать 0x2d, 0x30вместо '-', '0'. Не позволяет '+'подписать. Зачем в (int)ролях (int)strlen(snum)? UB, если вход "". UB, когда результат INT_MINиз-за intпереполнения сaccum += (snum[strIdx] - 0x30) * pow(10, idx);
chux - Восстановить Монику
@chux - этот код является демонстрационным. Есть легкие исправления того, что вы назвали потенциальными проблемами.
ButchDean
2
@ButchDean То, что вы описываете как «демонстрационный код», будет использоваться другими, которые не имеют ни малейшего представления о всех деталях. Только отрицательный балл и комментарии к этому ответу защищают их сейчас. На мой взгляд, «демонстрационный код» должен иметь гораздо более высокое качество.
Роланд Иллиг
@RolandIllig Вместо того, чтобы быть критически настроенными, разве не будет более полезным для других предложить собственное решение?
ButchDean
-1
Эта функция поможет вам
int strtoint_n(char* str,int n){int sign =1;int place =1;int ret =0;int i;for(i = n-1; i >=0; i--, place *=10){int c = str[i];switch(c){case'-':if(i ==0) sign =-1;elsereturn-1;break;default:if(c >='0'&& c <='9') ret +=(c -'0')* place;elsereturn-1;}}return sign * ret;}int strtoint(char* str){char* temp = str;int n =0;while(*temp !='\0'){
n++;
temp++;}return strtoint_n(str, n);}
Почему это все же? Одна из самых больших проблем с atoiдрузьями заключается в том, что если есть переполнение, это неопределенное поведение. Ваша функция не проверяет это. strtolи друзья делают.
Чад
1
Ага. Поскольку C - это не Python, я надеюсь, что люди, использующие язык C, знают об этих ошибках переполнения. У всего есть свои пределы.
Амит Чинтхака,
-1
Хорошо, у меня была та же проблема. Я нашел это решение. Это сработало для меня лучше всего. Я попробовал atoi (), но не сработал для меня. Вот мое решение:
void splitInput(int arr[],int sizeArr,char num[]){for(int i =0; i < sizeArr; i++)// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i]=(int)num[i]-48;}
//I think this way we could go :int my_atoi(constchar* snum){int nInt(0);int index(0);while(snum[index]){if(!nInt)
nInt=((int) snum[index])-48;else{
nInt =(nInt *=10)+((int) snum[index]-48);}
index++;}return(nInt);}int main(){
printf("Returned number is: %d\n", my_atoi("676987"));return0;}
Если вы хотите сделать это безопасно, на strtol()самом деле требуется изрядное количество кода. Он может возвращать LONG_MINлибо LONG_MAXлибо, если это фактическое преобразованное значение, либо при наличии недостаточного или переполнения, и он может возвращать 0 либо, если это фактическое значение, или если не было числа для преобразования. Вам нужно установить errno = 0перед звонком и проверить endptr.
Кит Томпсон
Решения, данные для разбора, не являются жизнеспособными решениями.
Ответы:
Есть
strtol
что лучше ИМО. Также я полюбилstrtonum
, так что используйте его, если он у вас есть (но помните, что он не переносимый):РЕДАКТИРОВАТЬ
Вы также можете быть заинтересованы
strtoumax
иstrtoimax
какие стандартные функции в C99. Например, вы могли бы сказать:Во всяком случае, держись подальше от
atoi
:источник
strtonum
? Я продолжаю получать неявное объявление о предупреждении#<stdlib.h>
. Тем не менее, вы можете использовать стандартнуюstrtoumax
альтернативу.Надежное
strtol
решение на основе C89С участием:
atoi
семьей)strtol
(например, без начальных пробелов и конечных символов мусора)GitHub вверх по течению .
На основе: https://stackoverflow.com/a/6154614/895245
источник
str2int()
. Педантичный: использоватьisspace((unsigned char) s[0])
.(unsigned char)
актеры могут иметь значение?l > INT_MAX
иl < INT_MIN
является бессмысленным целочисленным сравнением, поскольку любой результат всегда ложен. Что произойдет, если я изменю ихl >= INT_MAX
иl <= INT_MIN
уберу предупреждения? В ARM C long и int - это 32-разрядные подписанные базовые типы данных в ARM C и C ++l >= INT_MAX
неправильной функциональности: пример, возвращающийсяSTR2INT_OVERFLOW
с вводом"32767"
и 16-битнымint
. Используйте условную компиляцию. Пример .if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;
было бы лучше,if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}
чтобы вызывающий код , чтобы использоватьerrno
наint
вне диапазона. То же самое дляif (l < INT_MIN...
.Не используйте функции из
ato...
группы. Они сломаны и практически бесполезны. Было бы лучше использовать умеренно лучшее решениеsscanf
, хотя оно и не идеально.Для преобразования строки в целое число
strto...
должны использоваться функции из группы. В вашем конкретном случае это будетstrtol
функция.источник
sscanf
на самом деле имеет неопределенное поведение, если он пытается преобразовать число вне диапазона его типа (например,sscanf("999999999999999999999", "%d", &n)
).atoi
не обеспечивает значимой обратной связи об успехе / ошибке и имеет неопределенное поведение при переполнении.sscanf
обеспечивает обратную связь об успехе / неудаче (возвращаемое значение, что делает его «умеренно лучше»), но при переполнении все еще имеет неопределенное поведение Толькоstrtol
жизнеспособное решение.sscanf
. (Хотя, признаюсь, я иногда используюatoi
, обычно для программ, которые, как я ожидаю, не выживут более 10 минут, прежде чем я удалю источник.)Вы можете написать немного atoi () для удовольствия:
Вы также можете сделать его рекурсивным, который может быть старым в 3 строки =)
источник
code
((* str) - '0')code
"----1"
2) Имеет неопределенное поведение сint
переполнением, когда результат должен бытьINT_MIN
. Рассмотримmy_getnbr("-2147483648")
Просто хотел поделиться решением для unsigned long aswell.
источник
const char *
.48
значит? Вы предполагаете, что это значение того,'0'
где будет выполняться код? Пожалуйста, не навязывайте миру такие широкие предположения!'0'
как вы должны.источник
Вы всегда можете свернуть свое собственное!
Это будет делать то, что вы хотите без беспорядка.
источник
strto...
семейство функций. Они портативны и значительно лучше.0x2d, 0x30
вместо'-', '0'
. Не позволяет'+'
подписать. Зачем в(int)
ролях(int)strlen(snum)
? UB, если вход""
. UB, когда результатINT_MIN
из-заint
переполнения сaccum += (snum[strIdx] - 0x30) * pow(10, idx);
Эта функция поможет вам
Ссылка: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html
источник
atoi
друзьями заключается в том, что если есть переполнение, это неопределенное поведение. Ваша функция не проверяет это.strtol
и друзья делают.Хорошо, у меня была та же проблема. Я нашел это решение. Это сработало для меня лучше всего. Я попробовал atoi (), но не сработал для меня. Вот мое решение:
источник
источник
nInt = (nInt *= 10) + ((int) snum[index] - 48);
противnInt = nInt*10 + snum[index] - '0';
if(!nInt)
не нужно.В C ++ вы можете использовать такую функцию:
Это может помочь вам преобразовать любую строку в любой тип, такой как float, int, double ...
источник
Да, вы можете хранить целое число напрямую:
Если вам нужно разобрать строку
atoi
илиstrol
вы собираетесь выиграть конкурс «Самый короткий код».источник
strtol()
самом деле требуется изрядное количество кода. Он может возвращатьLONG_MIN
либоLONG_MAX
либо, если это фактическое преобразованное значение, либо при наличии недостаточного или переполнения, и он может возвращать 0 либо, если это фактическое значение, или если не было числа для преобразования. Вам нужно установитьerrno = 0
перед звонком и проверитьendptr
.