Saya mencoba mencari tahu apakah ada cara alternatif untuk mengubah string menjadi integer di C.
Saya secara teratur pola berikut ini dalam kode saya.
char s[] = "45";
int num = atoi(s);
Jadi, apakah ada cara yang lebih baik atau cara lain?
Saya mencoba mencari tahu apakah ada cara alternatif untuk mengubah string menjadi integer di C.
Saya secara teratur pola berikut ini dalam kode saya.
char s[] = "45";
int num = atoi(s);
Jadi, apakah ada cara yang lebih baik atau cara lain?
Jawaban:
Ada strtol
yang lebih baik IMO. Juga saya telah menyukai strtonum
, jadi gunakan jika Anda memilikinya (tapi ingat itu tidak portabel):
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
Anda mungkin juga tertarik strtoumax
danstrtoimax
yang merupakan fungsi standar di C99. Misalnya Anda bisa mengatakan:
uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */
Bagaimanapun, tinggal jauh dari atoi
:
Panggilan atoi (str) harus sama dengan:
(int) strtol(str, (char **)NULL, 10)
kecuali bahwa penanganan kesalahan mungkin berbeda. Jika nilai tidak dapat direpresentasikan, perilaku tidak terdefinisi .
strtonum
? Saya terus mendapatkan peringatan deklarasi implisit
#<stdlib.h>
. Namun, Anda bisa menggunakan strtoumax
alternatif standar .
strtol
Solusi berbasis C89 yang tangguh
Dengan:
atoi
keluarga)strtol
(mis. tidak ada spasi putih terkemuka atau karakter trash)#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;
}
Berdasarkan: https://stackoverflow.com/a/6154614/895245
str2int()
. Pedantic: gunakan isspace((unsigned char) s[0])
.
(unsigned char)
pemain bisa membuat perbedaan?
l > INT_MAX
dan l < INT_MIN
tidak ada perbandingan integer karena hasil mana pun selalu salah. Apa yang terjadi jika saya mengubahnya l >= INT_MAX
dan l <= INT_MIN
menghapus peringatan? Pada ARM C, panjang dan int adalah 32-bit bertanda tipe data dasar dalam ARM C dan C ++
l >= INT_MAX
menimbulkan fungsi yang salah: Contoh kembali STR2INT_OVERFLOW
dengan input "32767"
dan 16-bit int
. Gunakan kompilasi bersyarat. Contoh .
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;
akan lebih baik if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}
untuk memungkinkan kode panggilan untuk digunakan errno
di int
luar jangkauan. Sama untuk if (l < INT_MIN...
.
Jangan gunakan fungsi dari ato...
grup. Ini rusak dan hampir tidak berguna. Solusi yang cukup baik akan digunakan sscanf
, meskipun tidak sempurna juga.
Untuk mengonversi string menjadi integer, fungsi dari strto...
grup harus digunakan. Dalam kasus spesifik Anda itu akan strtol
berfungsi.
sscanf
sebenarnya memiliki perilaku yang tidak terdefinisi jika mencoba mengonversi angka di luar kisaran jenisnya (misalnya, sscanf("999999999999999999999", "%d", &n)
).
atoi
tidak memberikan umpan balik keberhasilan / kegagalan yang berarti dan memiliki perilaku yang tidak jelas pada luapan. sscanf
memberikan umpan balik keberhasilan / kegagalan (nilai pengembalian, yang membuatnya "lebih baik"), tetapi masih memiliki perilaku yang tidak terdefinisi pada overflow. Hanya strtol
solusi yang layak.
sscanf
. (Meskipun saya akui kadang-kadang saya gunakan atoi
, biasanya untuk program yang saya tidak harapkan untuk bertahan lebih dari 10 menit sebelum saya menghapus sumbernya.)
Anda dapat mengkodekan sedikit atoi () untuk bersenang-senang:
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);
}
Anda juga dapat membuatnya rekursif yang dapat berusia 3 baris =)
code
((* str) - '0')code
"----1"
2) Memiliki perilaku yang tidak terdefinisi dengan int
meluap ketika hasilnya seharusnya INT_MIN
. Pertimbangkanmy_getnbr("-2147483648")
Hanya ingin berbagi solusi untuk waktu yang lama tanpa tanda tangan.
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 *
.
48
artinya itu? Apakah Anda menganggap itu adalah nilai dari '0'
mana kode akan dijalankan? Tolong jangan menimbulkan asumsi luas seperti itu di dunia!
'0'
seperti yang seharusnya.
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;
}
Anda selalu dapat memutar sendiri!
#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;
}
Ini akan melakukan apa yang Anda inginkan tanpa kekacauan.
strto...
keluarga fungsi. Mereka portabel dan secara signifikan lebih baik.
0x2d, 0x30
bukan '-', '0'
. Tidak mengizinkan '+'
masuk. Mengapa (int)
dilemparkan (int)strlen(snum)
? UB jika input ""
. UB ketika hasilnya INT_MIN
karena int
melimpah denganaccum += (snum[strIdx] - 0x30) * pow(10, idx);
Fungsi ini akan membantu Anda
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
atoi
dan teman adalah bahwa jika ada luapan, itu adalah perilaku yang tidak terdefinisi. Fungsi Anda tidak memeriksa ini. strtol
dan teman-teman melakukannya.
Ok, saya punya masalah yang sama. Saya datang dengan solusi ini. Ini bekerja untuk saya yang terbaik. Saya memang mencoba atoi () tetapi tidak bekerja dengan baik untuk saya. Jadi di sini adalah solusi saya:
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)
tidak diperlukan.
Di C ++, Anda dapat menggunakan fungsi seperti itu:
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;
}
Ini dapat membantu Anda mengonversi string apa pun ke jenis apa pun seperti float, int, double ...
Ya, Anda dapat menyimpan integer secara langsung:
int num = 45;
Jika Anda harus menguraikan string, atoi
atau strol
akan memenangkan kontes "kode terpendek".
strtol()
sebenarnya membutuhkan jumlah kode yang adil. Hal ini dapat kembali LONG_MIN
atau LONG_MAX
baik jika itu nilai yang dikonversi sebenarnya atau jika ada sebuah underflow atau overflow, dan dapat kembali 0 baik jika itu nilai yang sebenarnya atau jika tidak ada nomor untuk mengkonversi. Anda perlu mengatur errno = 0
sebelum panggilan, dan memeriksa endptr
.