C言語のatoi/atof/strtol/strtod関数と自作関数で文字列を数値に変換する方法を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
C言語で文字列を数値に変換する方法と数値を文字列に変換する方法を紹介します.
本記事を読むと文字列と数値の相互変換をきちんと理解できます.
目次
atoi/atof関数で文字列を数値に変換
atoi/atof関数で文字列を数値に変換する方法を紹介します.
また,これらの関連関数も説明します.
atoi関数で文字列を符号あり整数に変換
1 2 3 |
int atoi(const char *nptr); long atol(const char *nptr); long long atoll(const char *nptr); |
atoi/atol/atoll関数で文字列を符号あり整数に変換する方法と,atoi関数の派生関数のatol/atoll関数を紹介します.
atoi/atol/atoll関数の利用例は以下のコードです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> int main(void) { char s1[] = "123"; char s2[] = "-4567"; printf("atoi(%s) = %d\n", s1, atoi(s1)); printf("atoi(%s) = %d\n", s2, atoi(s2)); printf("atol(%s) = %ld\n", s1, atol(s1)); printf("atol(%s) = %ld\n", s2, atol(s2)); printf("atoll(%s) = %lld\n", s1, atoll(s1)); printf("atoll(%s) = %lld\n", s2, atoll(s2)); return 0; } |
実行結果は以下になります.
printf関数のフォーマット指定子の%d,%ld,%lldを利用しているので,符号あり整数として正しく出力されています.
1 2 3 4 5 6 7 8 |
$ gcc atoi.c $ a.out atoi(123) = 123 atoi(-4567) = -4567 atol(123) = 123 atol(-4567) = -4567 atoll(123) = 123 atoll(-4567) = -4567 |
atof関数で文字列を浮動小数点数に変換
1 |
double atof(const char *nptr); |
atof関数は,文字列をdouble型の数値に変換します.
atof関数の利用例は以下のコードです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> int main(void) { char s1[] = "123.45"; char s2[] = "-4567.89"; printf("atof(%s) = %lf\n", s1, atof(s1)); printf("atof(%s) = %lf\n", s2, atof(s2)); return 0; } |
実行結果は以下になります.
printf関数のフォーマット指定子の%lfを利用しているので,浮動小数点数として正しく出力されています.
1 2 3 4 |
$ gcc atof.c $ a.out atof(123.45) = 123.450000 atof(-4567.89) = -4567.890000 |
atoi/atof関数の問題点
atoi/atof関数の問題点として,エラーチェックがないことが挙げられます.
数値以外の不正な文字が文字列に入っているコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> int main(void) { char s1[] = "y123z"; char s2[] = "0"; printf("atoi(%s) = %d\n", s1, atoi(s1)); printf("atoi(%s) = %d\n", s2, atoi(s2)); printf("atol(%s) = %ld\n", s1, atol(s1)); printf("atol(%s) = %ld\n", s2, atol(s2)); printf("atoll(%s) = %lld\n", s1, atoll(s1)); printf("atoll(%s) = %lld\n", s2, atoll(s2)); return 0; } |
実行結果は以下になります.
文字列"y123z"と"0"を数値に変換した結果が,両方とも0になってしまっています.これだと正しく変換できたかどうかわかりませんね.
1 2 3 4 5 6 7 8 |
$ gcc atoi_error.c $ a.out atoi(y123z) = 0 atoi(0) = 0 atol(y123z) = 0 atol(0) = 0 atoll(y123z) = 0 atoll(0) = 0 |
strtol/strtod関数で文字列を数値に変換
エラーチェック付きで文字列を数値に変換するstrtol/strtod関数を紹介します.
また,これらの関連関数も説明します.
strtol関数で文字列を符号あり整数に変換
1 2 |
long strtol(const char *nptr, char **endptr, int base); long long strtoll(const char *nptr, char **endptr, int base); |
strtol/strtoll関数は,エラーチェック付きで文字列を符号あり整数に変換します.
atoi/atol/atoll関数と同様に,第1引数に変換する文字列nptrを指定します.
第2引数のendptrがNULLでない場合は,最初に現れた不正な文字がstrtol関数により*endptrに保存されます.
文字列に有効な数字がなければ,strtol関数はnptrの元の値を*endptr に代入し0を返します.
特に,*nptr が '\0'以外で返された**endptr が'\0の場合,文字列全体が有効という意味になります.
第3引数のbaseに基数を設定することで,10進数だけでなく2~36進数を変換できます.
もしbaseが0の場合は,変換する先頭の文字列で何進数か判断します.
1文字目が0で2文字目が1から7の場合は8進数,1文字目が0で2文字目がxかXの場合は16進数として変換します.
返り値は,変換された数値になります.
数値がオーバーフローまたは アンダーフローした場合,大域変数errnoにERANGEまたはEINVALが設定されます.
strtol/strtoll関数の利用例は以下のコードです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <errno.h> void do_strtol(char *s, int base) { char *endptr; long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtol(s, &endptr, base); if (errno != 0) { perror("strtol()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %ld\n\n", __func__, val); } void do_strtoll(char *s, int base) { char *endptr; long long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtoll(s, &endptr, base); if (errno != 0) { perror("strtoll()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lld\n\n", __func__, val); } int main(void) { char s1[] = "123"; char s2[] = "123z"; char s3[] = "y123"; char s4[] = "y123z"; char s5[] = "yz"; char s6[] = "99999999999999999999999999999999999999999999999999999999"; do_strtol(s1, 10); do_strtol(s2, 10); do_strtol(s3, 10); do_strtol(s4, 10); do_strtol(s5, 10); do_strtol(s6, 10); do_strtoll(s1, 10); do_strtoll(s2, 10); do_strtoll(s3, 10); do_strtoll(s4, 10); do_strtoll(s5, 10); do_strtoll(s6, 10); return 0; } |
実行結果は以下になります.
文字列が"123"の場合だけ成功し,符号あり整数123に変換できています(3~4行目,21~22行目).
他の文字列の場合は,以下の理由でエラーになっています.
- 数値の後に無効な文字列がある場合(6~7行目,24~25行目)
- 無効な文字列の場合(9~10行目,12~13行目,15~16行目,27~28行目,30~31行目,33~34行目)
- オーバーフローが発生する場合(18~19行目,36~37行目)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ gcc strtol.c $ a.out do_strtol(): s = 123 do_strtol() is successful and val = 123 do_strtol(): s = 123z Error: invalid digits characters after number: "z" do_strtol(): s = y123 Error: cannot find valid digits. do_strtol(): s = y123z Error: cannot find valid digits. do_strtol(): s = yz Error: cannot find valid digits. do_strtol(): s = 99999999999999999999999999999999999999999999999999999999 strtol(): Numerical result out of range do_strtoll(): s = 123 do_strtoll() is successful and val = 123 do_strtoll(): s = 123z Error: invalid digits characters after number: "z" do_strtoll(): s = y123 Error: cannot find valid digits. do_strtoll(): s = y123z Error: cannot find valid digits. do_strtoll(): s = yz Error: cannot find valid digits. do_strtoll(): s = 99999999999999999999999999999999999999999999999999999999 strtoll(): Numerical result out of range |
strtoul関数で文字列を符号なし整数に変換
1 2 |
unsigned long strtoul(const char *nptr, char **endptr, int base); unsigned long long strtoull(const char *nptr, char **endptr, int base); |
strtoul/strtoull関数は,文字列を符号なし整数に変換します.
strtoul/strtoull関数は,いわゆるstrtol/strtoll関数の符号なしです.
strtoul/strtoull関数の利用例は以下のコードです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <errno.h> void do_strtoul(char *s, int base) { char *endptr; long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtoul(s, &endptr, base); if (errno != 0) { perror("strtoul()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %ld\n\n", __func__, val); } void do_strtoull(char *s, int base) { char *endptr; long long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtoull(s, &endptr, base); if (errno != 0) { perror("strtoull()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lld\n\n", __func__, val); } int main(void) { char s1[] = "123"; char s2[] = "123z"; char s3[] = "y123"; char s4[] = "y123z"; char s5[] = "yz"; char s6[] = "99999999999999999999999999999999999999999999999999999999"; do_strtoul(s1, 10); do_strtoul(s2, 10); do_strtoul(s3, 10); do_strtoul(s4, 10); do_strtoul(s5, 10); do_strtoul(s6, 10); do_strtoull(s1, 10); do_strtoull(s2, 10); do_strtoull(s3, 10); do_strtoull(s4, 10); do_strtoull(s5, 10); do_strtoull(s6, 10); return 0; } |
実行結果は以下になります.
strtol/strtoll関数と同様です.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ gcc strtoul.c $ a.out do_strtoul(): s = 123 do_strtoul() is successful and val = 123 do_strtoul(): s = 123z Error: invalid digits characters after number: "z" do_strtoul(): s = y123 Error: cannot find valid digits. do_strtoul(): s = y123z Error: cannot find valid digits. do_strtoul(): s = yz Error: cannot find valid digits. do_strtoul(): s = 99999999999999999999999999999999999999999999999999999999 strtoul(): Numerical result out of range do_strtoull(): s = 123 do_strtoull() is successful and val = 123 do_strtoull(): s = 123z Error: invalid digits characters after number: "z" do_strtoull(): s = y123 Error: cannot find valid digits. do_strtoull(): s = y123z Error: cannot find valid digits. do_strtoull(): s = yz Error: cannot find valid digits. do_strtoull(): s = 99999999999999999999999999999999999999999999999999999999 strtoull(): Numerical result out of range |
strtod関数で文字列を浮動小数点数に変換
1 2 3 |
double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); long double strtold(const char *nptr, char **endptr); |
strtod/strtof/strtold関数では,文字列を浮動小数点数に変換する関数です.
strtol/strtoll関数とは異なり,第3引数のbaseはありません.
他はほぼ同様です.
strtod/strtof/strtold関数の利用例は以下のコードです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <errno.h> void do_strtod(char *s) { char *endptr; double val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtod(s, &endptr); if (errno != 0) { perror("strtod()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lf\n\n", __func__, val); } void do_strtof(char *s) { char *endptr; float val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtof(s, &endptr); if (errno != 0) { perror("strtof()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %f\n\n", __func__, val); } void do_strtold(char *s) { char *endptr; long double val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtold(s, &endptr); if (errno != 0) { perror("strtold()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %Lf\n\n", __func__, val); } int main(void) { char s1[] = "123.45"; char s2[] = "123.45z"; char s3[] = "y123.45"; char s4[] = "y123.45z"; char s5[] = "yz"; char s6[] = "1.189731e+4933"; do_strtod(s1); do_strtod(s2); do_strtod(s3); do_strtod(s4); do_strtod(s5); do_strtod(s6); do_strtof(s1); do_strtof(s2); do_strtof(s3); do_strtof(s4); do_strtof(s5); do_strtof(s6); do_strtold(s1); do_strtold(s2); do_strtold(s3); do_strtold(s4); do_strtold(s5); do_strtold(s6); return 0; } |
実行結果は以下になります.
strtol/strtoll関数とほぼ同様です.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
$ gcc strtod.c $ a.out do_strtod(): s = 123.45 do_strtod() is successful and val = 123.450000 do_strtod(): s = 123.45z Error: invalid digits characters after number: "z" do_strtod(): s = y123.45 Error: cannot find valid digits. do_strtod(): s = y123.45z Error: cannot find valid digits. do_strtod(): s = yz Error: cannot find valid digits. do_strtod(): s = 1.189731e+4933 strtod(): Numerical result out of range do_strtof(): s = 123.45 do_strtof() is successful and val = 123.449997 do_strtof(): s = 123.45z Error: invalid digits characters after number: "z" do_strtof(): s = y123.45 Error: cannot find valid digits. do_strtof(): s = y123.45z Error: cannot find valid digits. do_strtof(): s = yz Error: cannot find valid digits. do_strtof(): s = 1.189731e+4933 strtof(): Numerical result out of range do_strtold(): s = 123.45 do_strtold() is successful and val = 123.450000 do_strtold(): s = 123.45z Error: invalid digits characters after number: "z" do_strtold(): s = y123.45 Error: cannot find valid digits. do_strtold(): s = y123.45z Error: cannot find valid digits. do_strtold(): s = yz Error: cannot find valid digits. do_strtold(): s = 1.189731e+4933 strtold(): Numerical result out of range |
自作関数で文字列を数値に変換
自作関数で文字列を数値に変換する方法を紹介します.
myatoi関数で文字列を符号あり整数に変換
myatoi関数で文字列を符号あり整数に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #include <ctype.h> #include <limits.h> #include <stdbool.h> unsigned int myatoui(const char *nptr) { unsigned int result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); if (nptr[0] == '+') { nptr++; } while (*nptr && (value = isdigit(*nptr) ? *nptr - '0' : UINT_MAX)) { if (value == UINT_MAX) { return 0; } result = result * 10 + value; nptr++; } if (ep != nptr) { return UINT_MAX; } return result; } int myatoi(const char *nptr) { if (*nptr == '-') { return -myatoui(nptr + 1); } return myatoui(nptr); } unsigned long myatoul(const char *nptr) { unsigned long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); if (nptr[0] == '+') { nptr++; } while (*nptr && (value = isdigit(*nptr) ? *nptr - '0' : ULONG_MAX)) { if (value == ULONG_MAX) { return 0; } result = result * 10 + value; nptr++; } if (ep != nptr) { return ULONG_MAX; } return result; } long myatol(const char *nptr) { if (*nptr == '-') { return -myatoul(nptr + 1); } return myatoul(nptr); } unsigned long long myatoull(const char *nptr) { unsigned long long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); if (nptr[0] == '+') { nptr++; } while (*nptr && (value = isdigit(*nptr) ? *nptr - '0' : ULLONG_MAX)) { if (value == ULLONG_MAX) { return 0; } result = result * 10 + value; nptr++; } if (ep != nptr) { return ULLONG_MAX; } return result; } long long myatoll(const char *nptr) { if (*nptr == '-') { return -myatoull(nptr + 1); } return myatoull(nptr); } int main(void) { char s1[] = "123"; char s2[] = "-4567"; printf("myatoi(%s) = %d\n", s1, myatoi(s1)); printf("myatoi(%s) = %d\n", s2, myatoi(s2)); printf("myatol(%s) = %ld\n", s1, myatol(s1)); printf("myatol(%s) = %ld\n", s2, myatol(s2)); printf("myatoll(%s) = %lld\n", s1, myatoll(s1)); printf("myatoll(%s) = %lld\n", s2, myatoll(s2)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 |
$ gcc myatoi.c $ a.out myatoi(123) = 123 myatoi(-4567) = -4567 myatol(123) = 123 myatol(-4567) = -4567 myatoll(123) = 123 myatoll(-4567) = -4567 |
myatof関数で文字列を浮動小数点数に変換
myatof関数で文字列を浮動小数点数に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #include <ctype.h> #include <limits.h> long lpow(long x, long y) { long ret = 1; int i; for (i = 0; i < y; i++) { ret *= x; } return ret; } double myatof(const char *nptr) { bool valid = false; double value = 0.0; double sign = 1.0; double psign; double small; double p; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { sign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; do { value = value * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); } if (*nptr == '.') { valid = false; nptr++; if (isdigit((unsigned char) *nptr)) { small = 0.1; valid = true; do { value += small * (*nptr - '0'); small *= 0.1; nptr++; } while (isdigit((unsigned char) *nptr)); } } if (valid && (*nptr == 'e' || *nptr == 'E')) { nptr++; valid = false; psign = +1.0; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { psign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; p = 0.0; do { p = p * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); value *= lpow(10.0, psign * p); } } return sign * value; } int main(void) { char s1[] = "123.45"; char s2[] = "-4567.89"; printf("myatof(%s) = %lf\n", s1, myatof(s1)); printf("myatof(%s) = %lf\n", s2, myatof(s2)); return 0; } |
実行結果は以下になります.
1 2 3 4 |
$ gcc myatof.c $ a.out myatof(123.45) = 123.450000 myatof(-4567.89) = -4567.890000 |
mystrtol関数で文字列を符号あり整数に変換
mystrol/mystrtoll関数で文字列を符号あり整数に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <ctype.h> #include <limits.h> #include <errno.h> long mystrtol(const char *nptr, char **endp, int base) { unsigned long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); int sign = 1; if (base != 0 && !(base >= 2 && base <= 36)) { errno = EINVAL; return 0; } if (*nptr == '-') { sign = -1; } if (nptr[0] == '+') { nptr++; } if (!base) { base = 10; if (*nptr == '0') { base = 8; nptr++; if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) { nptr++; base = 16; } } } else if (base == 16) { if (nptr[0] == '0' && toupper(nptr[1]) == 'X') { nptr += 2; } } while (isxdigit(*nptr) && (value = isdigit(*nptr) ? *nptr - '0' : toupper(*nptr) - 'A' + 10) < (unsigned long) base) { if (sign == 1 && result > (LONG_MAX - value) / base) { errno = ERANGE; return LONG_MAX; } else if (sign == -1 && result > ((unsigned long) LONG_MAX + 1 - value) / base) { errno = ERANGE; return LONG_MIN; } result = result * base + value; nptr++; } if (endp) { *endp = (char *) nptr; } if (ep != nptr) { return LONG_MAX; } return result; } void do_mystrtol(char *s, int base) { char *endptr; long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = mystrtol(s, &endptr, base); if (errno != 0) { perror("mystrtol()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %ld\n\n", __func__, val); } long long mystrtoll(const char *nptr, char **endp, int base) { unsigned long long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); int sign = 1; if (base != 0 && !(base >= 2 && base <= 36)) { errno = EINVAL; return 0; } if (*nptr == '-') { sign = -1; } if (nptr[0] == '+') { nptr++; } if (!base) { base = 10; if (*nptr == '0') { base = 8; nptr++; if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) { nptr++; base = 16; } } } else if (base == 16) { if (nptr[0] == '0' && toupper(nptr[1]) == 'X') { nptr += 2; } } while (isxdigit(*nptr) && (value = isdigit(*nptr) ? *nptr - '0' : toupper(*nptr) - 'A' + 10) < (unsigned long long) base) { if (sign == 1 && result > (LLONG_MAX - value) / base) { errno = ERANGE; return LLONG_MAX; } else if (sign == -1 && result > ((unsigned long) LLONG_MAX + 1 - value) / base) { errno = ERANGE; return LLONG_MIN; } result = result * base + value; nptr++; } if (endp) { *endp = (char *) nptr; } if (ep != nptr) { return LLONG_MAX; } return result; } void do_mystrtoll(char *s, int base) { char *endptr; long long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = mystrtoll(s, &endptr, base); if (errno != 0) { perror("mystrtoll()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lld\n\n", __func__, val); } int main(void) { char s1[] = "123"; char s2[] = "123z"; char s3[] = "y123"; char s4[] = "y123z"; char s5[] = "yz"; char s6[] = "99999999999999999999999999999999999999999999999999999999"; do_mystrtol(s1, 10); do_mystrtol(s2, 10); do_mystrtol(s3, 10); do_mystrtol(s4, 10); do_mystrtol(s5, 10); do_mystrtol(s6, 10); do_mystrtoll(s1, 10); do_mystrtoll(s2, 10); do_mystrtoll(s3, 10); do_mystrtoll(s4, 10); do_mystrtoll(s5, 10); do_mystrtoll(s6, 10); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ gcc mystrtol.c $ a.out do_mystrtol(): s = 123 do_mystrtol() is successful and val = 123 do_mystrtol(): s = 123z Error: invalid digits characters after number: "z" do_mystrtol(): s = y123 Error: cannot find valid digits. do_mystrtol(): s = y123z Error: cannot find valid digits. do_mystrtol(): s = yz Error: cannot find valid digits. do_mystrtol(): s = 99999999999999999999999999999999999999999999999999999999 mystrtol(): Numerical result out of range do_mystrtoll(): s = 123 do_mystrtoll() is successful and val = 123 do_mystrtoll(): s = 123z Error: invalid digits characters after number: "z" do_mystrtoll(): s = y123 Error: cannot find valid digits. do_mystrtoll(): s = y123z Error: cannot find valid digits. do_mystrtoll(): s = yz Error: cannot find valid digits. do_mystrtoll(): s = 99999999999999999999999999999999999999999999999999999999 mystrtoll(): Numerical result out of range |
mystrtoul関数で文字列を符号なし整数に変換
mystroul/mystrtoull関数で文字列を符号なし整数に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <ctype.h> #include <limits.h> #include <errno.h> unsigned long mystrtoul(const char *nptr, char **endp, int base) { unsigned long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); int sign = 1; if (base != 0 && !(base >= 2 && base <= 36)) { errno = EINVAL; return 0; } if (*nptr == '-') { sign = -1; } if (nptr[0] == '+') { nptr++; } if (!base) { base = 10; if (*nptr == '0') { base = 8; nptr++; if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) { nptr++; base = 16; } } } else if (base == 16) { if (nptr[0] == '0' && toupper(nptr[1]) == 'X') { nptr += 2; } } while (isxdigit(*nptr) && (value = isdigit(*nptr) ? *nptr - '0' : toupper(*nptr) - 'A' + 10) < (unsigned long) base) { if ((sign == 1 && result > (ULONG_MAX - value) / base) || (sign == -1 && result > ((unsigned long) LONG_MAX + 1 - value) / base)) { errno = ERANGE; return ULONG_MAX; } result = result * base + value; nptr++; } if (endp) { *endp = (char *) nptr; } if (ep != nptr) { return ULONG_MAX; } return result; } void do_mystrtoul(char *s, int base) { char *endptr; long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = mystrtoul(s, &endptr, base); if (errno != 0) { perror("mystrtoul()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %ld\n\n", __func__, val); } unsigned long long mystrtoull(const char *nptr, char **endp, int base) { unsigned long long result = 0, value; char *ep = (char *) nptr + strlen((char *) nptr); int sign = 1; if (base != 0 && !(base >= 2 && base <= 36)) { errno = EINVAL; return 0; } if (*nptr == '-') { sign = -1; } if (nptr[0] == '+') { nptr++; } if (!base) { base = 10; if (*nptr == '0') { base = 8; nptr++; if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) { nptr++; base = 16; } } } else if (base == 16) { if (nptr[0] == '0' && toupper(nptr[1]) == 'X') { nptr += 2; } } while (isxdigit(*nptr) && (value = isdigit(*nptr) ? *nptr - '0' : toupper(*nptr) - 'A' + 10) < (unsigned long long) base) { if ((sign == 1 && result > (ULLONG_MAX - value) / base) || (sign == -1 && result > ((unsigned long long) LLONG_MAX + 1 - value) / base)) { errno = ERANGE; return ULLONG_MAX; } result = result * base + value; nptr++; } if (endp) { *endp = (char *) nptr; } if (ep != nptr) { return ULLONG_MAX; } return result; } void do_mystrtoull(char *s, int base) { char *endptr; long long val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = mystrtoull(s, &endptr, base); if (errno != 0) { perror("mystrtoull()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lld\n\n", __func__, val); } int main(void) { char s1[] = "123"; char s2[] = "123z"; char s3[] = "y123"; char s4[] = "y123z"; char s5[] = "yz"; char s6[] = "99999999999999999999999999999999999999999999999999999999"; do_mystrtoul(s1, 10); do_mystrtoul(s2, 10); do_mystrtoul(s3, 10); do_mystrtoul(s4, 10); do_mystrtoul(s5, 10); do_mystrtoul(s6, 10); do_mystrtoull(s1, 10); do_mystrtoull(s2, 10); do_mystrtoull(s3, 10); do_mystrtoull(s4, 10); do_mystrtoull(s5, 10); do_mystrtoull(s6, 10); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ gcc mystrtoul.c $ a.out do_mystrtoul(): s = 123 do_mystrtoul() is successful and val = 123 do_mystrtoul(): s = 123z Error: invalid digits characters after number: "z" do_mystrtoul(): s = y123 Error: cannot find valid digits. do_mystrtoul(): s = y123z Error: cannot find valid digits. do_mystrtoul(): s = yz Error: cannot find valid digits. do_mystrtoul(): s = 99999999999999999999999999999999999999999999999999999999 mystrtoul(): Numerical result out of range do_mystrtoull(): s = 123 do_mystrtoull() is successful and val = 123 do_mystrtoull(): s = 123z Error: invalid digits characters after number: "z" do_mystrtoull(): s = y123 Error: cannot find valid digits. do_mystrtoull(): s = y123z Error: cannot find valid digits. do_mystrtoull(): s = yz Error: cannot find valid digits. do_mystrtoull(): s = 99999999999999999999999999999999999999999999999999999999 mystrtoull(): Numerical result out of range |
mystrtod関数で文字列を浮動小数点数に変換
mystrtod/mystrtof/mystrtold関数で文字列を浮動小数点数に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <ctype.h> #include <errno.h> long lpow(long x, long y) { long ret = 1; int i; for (i = 0; i < y; i++) { ret *= x; } return ret; } double mystrtod(const char *nptr, char **endptr) { const char *org = nptr; bool valid = false; double value = 0.0; double sign = 1.0; double psign; double small; double p; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { sign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; do { value = value * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); } if (*nptr == '.') { valid = false; nptr++; if (isdigit((unsigned char) *nptr)) { small = 0.1; valid = true; do { value += small * (*nptr - '0'); small *= 0.1; nptr++; } while (isdigit((unsigned char) *nptr)); } } if (valid && (*nptr == 'e' || *nptr == 'E')) { nptr++; valid = false; psign = +1.0; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { psign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; p = 0.0; do { p = p * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); value *= lpow(10.0, psign * p); } } if (valid) { *endptr = (char *) nptr; } else { *endptr = (char *) org; } return sign * value; } void do_strtod(char *s) { char *endptr; double val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = mystrtod(s, &endptr); if (errno != 0) { perror("strtod()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %lf\n\n", __func__, val); } float mystrtof(const char *nptr, char **endptr) { const char *org = nptr; bool valid = false; float value = 0.0; float sign = 1.0; float psign; float small; float p; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { sign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; do { value = value * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); } if (*nptr == '.') { valid = false; nptr++; if (isdigit((unsigned char) *nptr)) { small = 0.1; valid = true; do { value += small * (*nptr - '0'); small *= 0.1; nptr++; } while (isdigit((unsigned char) *nptr)); } } if (valid && (*nptr == 'e' || *nptr == 'E')) { nptr++; valid = false; psign = +1.0; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { psign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; p = 0.0; do { p = p * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); value *= lpow(10.0, psign * p); } } if (valid) { *endptr = (char *) nptr; } else { *endptr = (char *) org; } return sign * value; } void do_strtof(char *s) { char *endptr; float val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtof(s, &endptr); if (errno != 0) { perror("strtof()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %f\n\n", __func__, val); } long double mystrtold(const char *nptr, char **endptr) { const char *org = nptr; bool valid = false; long double value = 0.0; long double sign = 1.0; long double psign; long double small; long double p; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { sign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; do { value = value * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); } if (*nptr == '.') { valid = false; nptr++; if (isdigit((unsigned char) *nptr)) { small = 0.1; valid = true; do { value += small * (*nptr - '0'); small *= 0.1; nptr++; } while (isdigit((unsigned char) *nptr)); } } if (valid && (*nptr == 'e' || *nptr == 'E')) { nptr++; valid = false; psign = +1.0; if (*nptr == '+') { nptr++; } else if (*nptr == '-') { psign = -1.0; nptr++; } if (isdigit((unsigned char) *nptr)) { valid = true; p = 0.0; do { p = p * 10.0 + (*nptr - '0'); nptr++; } while (isdigit((unsigned char) *nptr)); value *= lpow(10.0, psign * p); } } if (valid) { *endptr = (char *) nptr; } else { *endptr = (char *) org; } return sign * value; } void do_strtold(char *s) { char *endptr; long double val; errno = 0; printf("%s(): s = %s\n", __func__, s); val = strtold(s, &endptr); if (errno != 0) { perror("strtold()"); printf("\n"); return; } if (endptr == s) { fprintf(stderr, "Error: cannot find valid digits.\n\n"); return; } if (*endptr != '\0') { fprintf(stderr, "Error: invalid digits characters after number: \"%s\"\n\n", endptr); return; } printf("%s() is successful and val = %Lf\n\n", __func__, val); } int main(void) { char s1[] = "123.45"; char s2[] = "123.45z"; char s3[] = "y123.45"; char s4[] = "y123.45z"; char s5[] = "yz"; char s6[] = "1.189731e+4933"; do_strtod(s1); do_strtod(s2); do_strtod(s3); do_strtod(s4); do_strtod(s5); do_strtod(s6); do_strtof(s1); do_strtof(s2); do_strtof(s3); do_strtof(s4); do_strtof(s5); do_strtof(s6); do_strtold(s1); do_strtold(s2); do_strtold(s3); do_strtold(s4); do_strtold(s5); do_strtold(s6); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
$ gcc mystrtod.c $ a.out do_strtod(): s = 123.45 do_strtod() is successful and val = 123.450000 do_strtod(): s = 123.45z Error: invalid digits characters after number: "z" do_strtod(): s = y123.45 Error: cannot find valid digits. do_strtod(): s = y123.45z Error: cannot find valid digits. do_strtod(): s = yz Error: cannot find valid digits. do_strtod(): s = 1.189731e+4933 strtod(): Numerical result out of range do_strtof(): s = 123.45 do_strtof() is successful and val = 123.449997 do_strtof(): s = 123.45z Error: invalid digits characters after number: "z" do_strtof(): s = y123.45 Error: cannot find valid digits. do_strtof(): s = y123.45z Error: cannot find valid digits. do_strtof(): s = yz Error: cannot find valid digits. do_strtof(): s = 1.189731e+4933 strtof(): Numerical result out of range do_strtold(): s = 123.45 do_strtold() is successful and val = 123.450000 do_strtold(): s = 123.45z Error: invalid digits characters after number: "z" do_strtold(): s = y123.45 Error: cannot find valid digits. do_strtold(): s = y123.45z Error: cannot find valid digits. do_strtold(): s = yz Error: cannot find valid digits. do_strtold(): s = 1.189731e+4933 strtold(): Numerical result out of range |
自作関数で数値を文字列に変換
数値を文字列に変換する標準ライブラリ関数はありません.
なので,自作関数で数値を文字列に変換する方法を紹介します.
myitoa関数で整数を文字列に変換
myitoa関数で整数を文字列に変換するコードは以下になります.
符号ありと符号なしの両方やに対応しています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #include <ctype.h> #define BUFSIZE 64 void myxtoa(unsigned long long val, char *str, int base, bool negative) { char *p; char *firstdig; char temp; unsigned long long digval; if (base != 0 && !(base >= 2 && base <= 36)) { fprintf(stderr, "Error: invalid base %u\n", base); return; } p = str; if (negative) { *p++ = '-'; val = (unsigned long long)(-(long long) val); } if (!base) { base = 10; if (*str == '0') { base = 8; str++; if ((toupper(*str) == 'X') && isxdigit(str[1])) { str++; base = 16; } } } else if (base == 16) { if (str[0] == '0' && toupper(str[1]) == 'X') { str += 2; } } firstdig = p; do { digval = (unsigned long long)(val % base); val /= base; if (digval > 9) { *p++ = (char)(digval - 10 + 'a'); } else { *p++ = (char)(digval + '0'); } } while (val > 0); *p-- = '\0'; do { temp = *p; *p = *firstdig; *firstdig = temp; p--; firstdig++; } while (firstdig < p); } char *myitoa(int val, char *str, int base) { if (base == 10 && val < 0) { myxtoa(val, str, base, true); } else { myxtoa(val, str, base, false); } return str; } char *myltoa(long val, char *str, int base) { myxtoa(val, str, base, (base == 10 && val < 0)); return str; } char *mylltoa(long long val, char *str, int base) { myxtoa(val, str, base, (base == 10 && val < 0)); return str; } int main(void) { int i1 = 123; int i2 = -456; long l1 = 1234; long l2 = -5678; long long ll1 = 12345; long long ll2 = -67890; char s[BUFSIZE]; myitoa(i1, s, 10); printf("i1 = %d, s = %s\n", i1, s); myitoa(i2, s, 10); printf("i2 = %d, s = %s\n", i2, s); myltoa(l1, s, 10); printf("l1 = %ld, s = %s\n", l1, s); myltoa(l2, s, 10); printf("l2 = %ld, s = %s\n", l2, s); mylltoa(l1, s, 10); printf("ll1 = %lld, s = %s\n", ll1, s); mylltoa(l2, s, 10); printf("ll2 = %lld, s = %s\n", ll2, s); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 |
$ gcc myitoa.c $ a.out i1 = 123, s = 123 i2 = -456, s = -456 l1 = 1234, s = 1234 l2 = -5678, s = -5678 ll1 = 12345, s = 1234 ll2 = -67890, s = -5678 |
myftoa関数で浮動小数点数を文字列に変換
myftoa関数で浮動小数点数を文字列に変換するコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define BUFSIZE 64 long lpow(long x, long y) { long ret = 1; int i; for (i = 0; i < y; i++) { ret *= x; } return ret; } char *myftoa(double d, char *buf, int precision) { char *ptr = buf; char *p = ptr; char *p1; char c; long int_part; double rounders; if (d < 0) { d = -d; *ptr++ = '-'; } if (precision < 0) { precision = 1; } rounders = 0.5 / lpow(10.0, precision); if (precision) { d += rounders; } int_part = d; d -= int_part; if (!int_part) { *ptr++ = '0'; } else { p = ptr; while (int_part) { *p++ = '0' + int_part % 10; int_part /= 10; } p1 = p; while (p > ptr) { c = *--p; *p = *ptr; *ptr++ = c; } ptr = p1; } if (precision) { *ptr++ = '.'; while (precision--) { d *= 10.0; c = d; *ptr++ = '0' + c; d -= c; } } *ptr = '\0'; return buf; } int main(void) { double d1 = 123.45; double d2 = -4557.89; char s[BUFSIZE]; myftoa(d1, s, 6); printf("d1 = %lf, s = %s\n", d1, s); myftoa(d2, s, 6); printf("d2 = %lf, s = %s\n", d2, s); return 0; } |
実行結果は以下になります.
1 2 3 4 |
$ gcc myftoa.c $ a.out d1 = 123.450000, s = 123.450000 d2 = -4557.890000, s = -4557.890000 |
まとめ
C言語のatoi/atof関数で文字列を数値に変換する方法を紹介しました.
また,これらの関数はエラーチェックがないため,エラーチェックがあるstrtol/strtod関数,逆に数値を文字列に変換する自作関数も紹介しました.
C言語で文字列と数値の相互変換をしたいあなたにおすすめのコードですので,是非利用しましょう!
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!