C tamsayı dize dönüştürme alternatif bir yol olup olmadığını bulmaya çalışıyorum.
Kodumda düzenli olarak aşağıdakileri düzenlerim.
char s[] = "45";
int num = atoi(s);
Peki, daha iyi ya da başka bir yol var mı?
C tamsayı dize dönüştürme alternatif bir yol olup olmadığını bulmaya çalışıyorum.
Kodumda düzenli olarak aşağıdakileri düzenlerim.
char s[] = "45";
int num = atoi(s);
Peki, daha iyi ya da başka bir yol var mı?
Yanıtlar:
Orada strtoldaha iyi IMO olan. Ayrıca ben bir sevme aldı strtonum, bu yüzden varsa (ama taşınabilir olmadığını unutmayın) kullanın:
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
Ayrıca ilginizi çekebilir strtoumaxvestrtoimax bunlar C99'da standart işlevlerdir. Örneğin şöyle diyebilirsiniz:
uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */
Her neyse, uzak durun atoi:
Çağrı atoi (str) aşağıdakilere eşit olacaktır:
(int) strtol(str, (char **)NULL, 10)hataların ele alınması farklı olabilir. Değer temsil edilemiyorsa, davranış tanımsızdır .
strtonum? Örtülü bir bildirim uyarısı alıyorum
#<stdlib.h>. Ancak, standart strtoumaxalternatifi kullanabilirsiniz .
Sağlam C89 strtoltabanlı çözüm
İle:
atoiailede olduğu gibi)strtol(ör. önde gelen boşluk veya sondaki çöp karakteri yok)#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum {
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", (long int)INT_MAX + 1L);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
}
/* int underflow */
if (LONG_MIN < INT_MIN) {
sprintf(s, "%ld", (long int)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(). Bilgiçlik taslayan: kullanın isspace((unsigned char) s[0]).
(unsigned char)fark yaratabileceğini biraz daha açıklayabilir misiniz ?
l > INT_MAXve l < INT_MINher iki sonuç da her zaman yanlış olduğundan anlamsız tamsayı karşılaştırmasıdır. Uyarıları değiştirir l >= INT_MAXve l <= INT_MINuyarıları temizlersem ne olur ? ARM C'de, uzun ve int 32-bit imzalı ARM C ve C ++ 'da temel veri türleri
l >= INT_MAXyanlış işlevsellik için kod değiştirme : STR2INT_OVERFLOWGiriş "32767"ve 16 bit ile dönen örnek int. Koşullu bir derleme kullanın. Örnek .
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;olarak daha iyi olurdu if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}kullanmak için kod çağıran izin errnoüzerine intdışarı aralık. Aynı if (l < INT_MIN....
ato...Gruptaki işlevleri kullanmayın . Bunlar kırık ve neredeyse işe yaramaz. Mükemmel sscanfolmasa da, nispeten daha iyi bir çözüm kullanmak olacaktır .
Dizeyi tamsayıya dönüştürmek için strto...gruptan işlevler kullanılmalıdır. Özel durumunuzda bu strtolişlev olacaktır .
sscanfaslında bir sayıyı kendi türünün aralığının dışına dönüştürmeye çalışırsa tanımlanmamış bir davranışı vardır (örneğin, sscanf("999999999999999999999", "%d", &n)).
atoianlamlı bir başarı / başarısızlık geri bildirimi sağlamaz ve taşma konusunda tanımlanmamış bir davranışa sahiptir. sscanftürlerin başarı / başarısızlık geri bildirimlerini sağlar (dönüş değeri, "orta derecede daha iyi" yapan şeydir), ancak taşma konusunda hala tanımlanmamış bir davranışa sahiptir. Sadece strtoluygulanabilir bir çözümdür.
sscanf. (Her ne kadar itiraf etsem de atoi, genellikle kaynağı silmeden önce 10 dakikadan fazla hayatta kalmayı beklemediğim programlar için kullanıyorum .)
Eğlenmek için biraz atoi () kodlayabilirsiniz:
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);
}
Ayrıca 3 satırda eski olabilir özyinelemeli yapabilirsiniz =)
code((* str) - '0')code
"----1" 2) intSonuç olması gerektiğinde taşma ile tanımlanmamış bir davranışa sahiptir INT_MIN. Düşününmy_getnbr("-2147483648")
Sadece imzasız uzun bir süre için bir çözüm paylaşmak istedim.
unsigned long ToUInt(char* str)
{
unsigned long mult = 1;
unsigned long 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 *.
48anlama geliyor? '0'Kodun çalışacağı yerin değeri olduğunu mu düşünüyorsunuz? Lütfen dünyaya bu kadar geniş varsayımlar getirmeyin!
'0'gerektiği gibi kullanın .
int atoi(const char* 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;
}
Sen her zaman kendi rulo!
#include <stdio.h>
#include <string.h>
#include <math.h>
int my_atoi(const char* snum)
{
int idx, strIdx = 0, accum = 0, numIsNeg = 0;
const unsigned int 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;
else
return accum * -1;
}
int main()
{
/* Tests... */
printf("Returned number is: %d\n", my_atoi("34574"));
printf("Returned number is: %d\n", my_atoi("-23"));
return 0;
}
Bu, dağınıklık olmadan istediğinizi yapar.
strto...Fonksiyon ailesini kullanmamak için hiçbir sebep yok . Taşınabilir ve çok daha iyi.
0x2d, 0x30Bunun yerine kullanmak garip '-', '0'. İşarete izin vermiyor '+'. Neden (int)girmelisin (int)strlen(snum)? Giriş ise UB "". Sonucudur UB INT_MINnedeniyle inttaşmaaccum += (snum[strIdx] - 0x30) * pow(10, idx);
Bu işlev size yardımcı olacaktır
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;
else return -1;
break;
default:
if (c >= '0' && c <= '9') ret += (c - '0') * place;
else return -1;
}
}
return sign * ret;
}
int strtoint(char* str)
{
char* temp = str;
int n = 0;
while (*temp != '\0')
{
n++;
temp++;
}
return strtoint_n(str, n);
}
Ref: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html
atoiVe arkadaşları ile en büyük sorunlarından biri taşma varsa, tanımsız davranış olmasıdır. İşleviniz bunu kontrol etmez. strtolve arkadaşlar.
Tamam, ben de aynı sorunu yaşadım. Bu çözümü buldum. Benim için en iyisi çalıştı.
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(const char* 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"));
return 0;
}
nInt = (nInt *= 10) + ((int) snum[index] - 48);vs. nInt = nInt*10 + snum[index] - '0'; if(!nInt)gerekli değildir.
C ++ 'da böyle bir işlev kullanabilirsiniz:
template <typename T>
T to(const std::string & s)
{
std::istringstream stm(s);
T result;
stm >> result;
if(stm.tellg() != s.size())
throw error;
return result;
}
Bu, herhangi bir dizeyi float, int, double gibi herhangi bir türe dönüştürmenize yardımcı olabilir ...
Evet, tamsayıyı doğrudan saklayabilirsiniz:
int num = 45;
Bir dizeyi ayrıştırmanız gerekiyorsa atoiveya strol"en kısa kod miktarı" yarışmasını kazanacaksanız.
strtol()aslında makul miktarda kod gerektirir. Dönebilir LONG_MINya LONG_MAX da gerçek dönüştürülmüş değerse veya bir taşma veya taşma varsa ve gerçek değerse veya dönüştürülecek sayı yoksa 0 döndürebilir. errno = 0Aramadan önce ayarlamanız ve öğesini kontrol etmeniz gerekir endptr.