Tag dan judul Anda mengatakan Anda menginginkan solusi dalam C, tetapi pertanyaan Anda mengatakan C atau C ++. Yang mana yang kamu mau?
Dalam silico
1
@Yann, Maaf atas kebingungan itu. Saya lebih suka C.
user618677
1
Ini berfungsi, tetapi ini bukan cara yang disarankan, karena tidak ada cara untuk menangani kesalahan. Jangan pernah gunakan ini dalam kode produksi kecuali Anda dapat mempercayai input 100%.
Uwe Geuder
1
Tetapkan 'lebih baik', dan nyatakan dengan jelas mengapa Anda membutuhkan cara lain.
Marquis of Lorne
3
@ EJP Hanya untuk meningkatkan diri.
user618677
Jawaban:
185
Ada strtolyang lebih baik IMO. Juga saya telah menyukai strtonum, jadi gunakan jika Anda memilikinya (tapi ingat itu tidak portabel):
untuk apa saya perlu memasukkan strtonum? Saya terus mendapatkan peringatan deklarasi implisit
jsj
@ trideceth12 Pada sistem yang tersedia, harus dinyatakan dalam #<stdlib.h>. Namun, Anda bisa menggunakan strtoumaxalternatif standar .
cnicutar
4
Jawaban ini sepertinya tidak lebih pendek dari kode pertama si penanya.
Azurespot
11
@NoniA. Keringkasan selalu baik, tetapi tidak dengan mengorbankan kebenaran.
cnicutar
6
Tidak terlalu salah dengan tidak aman. atoi () berfungsi jika input valid. Tetapi bagaimana jika Anda melakukan atoi ("kucing")? strtol () telah mendefinisikan perilaku jika nilai tidak dapat direpresentasikan sebagai panjang, atoi () tidak.
Daniel B.
27
strtolSolusi berbasis C89 yang tangguh
Dengan:
tidak ada perilaku yang tidak jelas (seperti yang bisa terjadi dengan atoikeluarga)
definisi integer yang lebih ketat daripada strtol(mis. tidak ada spasi putih terkemuka atau karakter trash)
klasifikasi kasus kesalahan (mis. untuk memberikan pesan kesalahan yang berguna bagi pengguna)
sebuah "tes"
#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;}
Bagus kuat str2int(). Pedantic: gunakan isspace((unsigned char) s[0]).
chux
@ chux terima kasih! Bisakah Anda jelaskan lebih banyak mengapa para (unsigned char)pemain bisa membuat perbedaan?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Kompiler IAR C memperingatkan itu l > INT_MAXdan l < INT_MINtidak ada perbandingan integer karena hasil mana pun selalu salah. Apa yang terjadi jika saya mengubahnya l >= INT_MAXdan l <= INT_MINmenghapus peringatan? Pada ARM C, panjang dan int adalah 32-bit bertanda tipe data dasar dalam ARM C dan C ++
ecle
@ hapus perubahan kode untuk l >= INT_MAXmenimbulkan fungsi yang salah: Contoh kembali STR2INT_OVERFLOWdengan input "32767"dan 16-bit int. Gunakan kompilasi bersyarat. Contoh .
chux - Reinstate Monica
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 errnodi intluar jangkauan. Sama untuk if (l < INT_MIN....
chux - Reinstate Monica
24
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 strtolberfungsi.
sscanfsebenarnya memiliki perilaku yang tidak terdefinisi jika mencoba mengonversi angka di luar kisaran jenisnya (misalnya, sscanf("999999999999999999999", "%d", &n)).
Keith Thompson
1
@Keith Thompson: Itulah yang saya maksud. atoitidak memberikan umpan balik keberhasilan / kegagalan yang berarti dan memiliki perilaku yang tidak jelas pada luapan. sscanfmemberikan umpan balik keberhasilan / kegagalan (nilai pengembalian, yang membuatnya "lebih baik"), tetapi masih memiliki perilaku yang tidak terdefinisi pada overflow. Hanya strtolsolusi yang layak.
AnT
1
Sepakat; Saya hanya ingin menekankan masalah yang berpotensi fatal 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.)
Keith Thompson
5
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 =)
Terima kasih banyak .. Tapi bisakah Anda memberi tahu saya bagaimana kode di bawah ini bekerja? code((* str) - '0')code
user618677
sebuah karakter memiliki nilai ascii. Jika Anda bukan tipe linux: man ascii di shell atau jika tidak pergi ke: table-ascii.com . Anda akan melihat bahwa karakter '0' = 68 (saya pikir) untuk int. Jadi untuk mendapatkan angka '9' ('0' + 9) maka Anda mendapatkan 9 = '9' - '0'. Kau mengerti?
jDourlens
1
1) Kode memungkinkan "----1" 2) Memiliki perilaku yang tidak terdefinisi dengan intmeluap ketika hasilnya seharusnya INT_MIN. Pertimbangkanmy_getnbr("-2147483648")
chux - Reinstate Monica
Terima kasih atas ketepatannya, itu hanya untuk menunjukkan sedikit contoh. Seperti yang dikatakan untuk bersenang-senang dan belajar. Anda harus menggunakan lib standar untuk tugas semacam ini. Lebih cepat dan lebih aman!
jDourlens
2
Hanya ingin berbagi solusi untuk waktu yang lama tanpa tanda tangan.
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;}
Tidak menangani overflow. Juga, parameternya harus const char *.
Roland Illig
2
Plus, apa 48artinya itu? Apakah Anda menganggap itu adalah nilai dari '0'mana kode akan dijalankan? Tolong jangan menimbulkan asumsi luas seperti itu di dunia!
Toby Speight
@TobySpeight Ya saya menganggap 48 mewakili '0' di tabel ascii.
Yakub
3
Tidak semua dunia adalah ASCII - gunakan saja '0'seperti yang seharusnya.
Toby Speight
disarankan untuk menggunakan fungsi strtoul sebagai gantinya.
rapidclock
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;}
Ini akan melakukan apa yang Anda inginkan tanpa kekacauan.
Tapi kenapa? Ini tidak memeriksa luapan dan hanya mengabaikan nilai sampah. Tidak ada alasan untuk tidak menggunakan strto...keluarga fungsi. Mereka portabel dan secara signifikan lebih baik.
chad
1
Aneh untuk digunakan, 0x2d, 0x30bukan '-', '0'. Tidak mengizinkan '+'masuk. Mengapa (int)dilemparkan (int)strlen(snum)? UB jika input "". UB ketika hasilnya INT_MINkarena intmelimpah denganaccum += (snum[strIdx] - 0x30) * pow(10, idx);
chux - Reinstate Monica
@ chux - Kode ini adalah kode demonstrasi. Ada perbaikan mudah untuk apa yang Anda gambarkan sebagai masalah potensial.
ButchDean
2
@ButchDean Apa yang Anda gambarkan sebagai "kode demonstrasi" akan digunakan oleh orang lain yang tidak memiliki petunjuk tentang semua detail. Hanya skor negatif dan komentar pada jawaban ini yang melindungi mereka sekarang. Menurut saya, "kode demonstrasi" harus memiliki kualitas yang jauh lebih tinggi.
Roland Illig
@RolandIllig Daripada bersikap kritis, bukankah akan lebih bermanfaat bagi orang lain untuk benar-benar memberikan solusi Anda sendiri?
ButchDean
-1
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;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);}
Mengapa melakukan ini? Salah satu masalah terbesar dengan atoidan teman adalah bahwa jika ada luapan, itu adalah perilaku yang tidak terdefinisi. Fungsi Anda tidak memeriksa ini. strtoldan teman-teman melakukannya.
chad
1
Ya. Karena C bukan Python, saya harap orang-orang yang menggunakan bahasa C menyadari kesalahan jenis ini. Semuanya memiliki batasnya sendiri.
Amith Chinthaka
-1
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(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;}
Jika Anda ingin melakukannya dengan aman, strtol()sebenarnya membutuhkan jumlah kode yang adil. Hal ini dapat kembali LONG_MINatau LONG_MAXbaik 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 = 0sebelum panggilan, dan memeriksa endptr.
Keith Thompson
Solusi yang diberikan kepada parse, bukanlah solusi yang layak.
Jawaban:
Ada
strtol
yang lebih baik IMO. Juga saya telah menyukaistrtonum
, jadi gunakan jika Anda memilikinya (tapi ingat itu tidak portabel):EDIT
Anda mungkin juga tertarik
strtoumax
danstrtoimax
yang merupakan fungsi standar di C99. Misalnya Anda bisa mengatakan:Bagaimanapun, tinggal jauh dari
atoi
:sumber
strtonum
? Saya terus mendapatkan peringatan deklarasi implisit#<stdlib.h>
. Namun, Anda bisa menggunakanstrtoumax
alternatif standar .strtol
Solusi berbasis C89 yang tangguhDengan:
atoi
keluarga)strtol
(mis. tidak ada spasi putih terkemuka atau karakter trash)GitHub hulu .
Berdasarkan: https://stackoverflow.com/a/6154614/895245
sumber
str2int()
. Pedantic: gunakanisspace((unsigned char) s[0])
.(unsigned char)
pemain bisa membuat perbedaan?l > INT_MAX
danl < INT_MIN
tidak ada perbandingan integer karena hasil mana pun selalu salah. Apa yang terjadi jika saya mengubahnyal >= INT_MAX
danl <= 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 kembaliSTR2INT_OVERFLOW
dengan input"32767"
dan 16-bitint
. Gunakan kompilasi bersyarat. Contoh .if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;
akan lebih baikif (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}
untuk memungkinkan kode panggilan untuk digunakanerrno
diint
luar jangkauan. Sama untukif (l < INT_MIN...
.Jangan gunakan fungsi dari
ato...
grup. Ini rusak dan hampir tidak berguna. Solusi yang cukup baik akan digunakansscanf
, meskipun tidak sempurna juga.Untuk mengonversi string menjadi integer, fungsi dari
strto...
grup harus digunakan. Dalam kasus spesifik Anda itu akanstrtol
berfungsi.sumber
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. Hanyastrtol
solusi yang layak.sscanf
. (Meskipun saya akui kadang-kadang saya gunakanatoi
, 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:
Anda juga dapat membuatnya rekursif yang dapat berusia 3 baris =)
sumber
code
((* str) - '0')code
"----1"
2) Memiliki perilaku yang tidak terdefinisi denganint
meluap ketika hasilnya seharusnyaINT_MIN
. Pertimbangkanmy_getnbr("-2147483648")
Hanya ingin berbagi solusi untuk waktu yang lama tanpa tanda tangan.
sumber
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.sumber
Anda selalu dapat memutar sendiri!
Ini akan melakukan apa yang Anda inginkan tanpa kekacauan.
sumber
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 hasilnyaINT_MIN
karenaint
melimpah denganaccum += (snum[strIdx] - 0x30) * pow(10, idx);
Fungsi ini akan membantu Anda
Ref: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html
sumber
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:
sumber
sumber
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:
Ini dapat membantu Anda mengonversi string apa pun ke jenis apa pun seperti float, int, double ...
sumber
Ya, Anda dapat menyimpan integer secara langsung:
Jika Anda harus menguraikan string,
atoi
ataustrol
akan memenangkan kontes "kode terpendek".sumber
strtol()
sebenarnya membutuhkan jumlah kode yang adil. Hal ini dapat kembaliLONG_MIN
atauLONG_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 mengaturerrno = 0
sebelum panggilan, dan memeriksaendptr
.