下のような感じで数字の文字列を整数値に変換するプログラムを作ってみました。このプログラムを整数型の最大値より大きな値、または最小値よりも小さな値となった場合には変換しないようにしたいんですが、どのようにしたらうまくいきますか?
また、下のプログラムでダメな部分があれば教えてください!!
#include<stdio.h> #include<ctype.h> int str2value(const char suuji[]) { if(isdigit(suuji[0])){ int seisuu = suuji[0] - '0'; for(int i = 1; isdigit(suuji[i]); i++){ seisuu *= 10; seisuu += suuji[i] - '0'; } return seisuu; } else return 0; } int main(void) { char s[256]; while(scanf("%s", s) == 1){ const int n = str2value(s); printf("%d\n", n); } return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/08/18 22:30
回答4件
0
sizeof(int) < sizeof(long long) の前提で書いてみました。
C
1#include <stdio.h> // scanf, printf 2#include <ctype.h> // isspace, isdigit 3#include <limits.h> // INT_MIN, INT_MAX 4 5int str2value(const char suuji[]) 6{ 7 unsigned char *p = (unsigned char *)suuji; 8 while (isspace(*p)) p++; 9 int neg = 0; 10 if (*p == '-') neg = 1, p++; 11 else if (*p == '+') p++; 12 if (!isdigit(*p)) return 0; 13 long long val = *p++ - '0'; 14 while (isdigit(*p)) { 15 val = val * 10 + *p++ - '0'; 16 if (neg ? -val < INT_MIN : val > INT_MAX) return 0; 17 } 18 return (int)(neg ? -val : val); 19} 20 21int main(void) 22{ 23 char s[256]; 24 while (scanf("%255s", s) == 1){ 25 const int n = str2value(s); 26 printf("%d\n", n); 27 } 28 return 0; 29}
atoi と同じ仕様で、+ と - の符号があってもよく、
さらにその前に空白があってもよいものとします。
また、数字の後に数字以外の文字があってもよいものとします。
isdigit(c) の c は unsigned charの値、または EOF の値なので、
-1~255 しか許されません。
char が符号付で -128~127 だと負の値を渡すことがあって動作は未定義です。
半角片仮名や平仮名や漢字だとそうなります。
それも考慮して unsigned char *p; を使っています。
投稿2020/08/19 13:51
総合スコア8224
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
愚直に書いてみたら意外と面倒でした。
(もっとスマートな回答がされることを期待します。)
入力された文字列がint型の最大最小範囲内ならint型の変数に代入し同じものを出力する。
数値に変換出来ない文字だったり範囲外ならint型ではない旨のメッセージを出力する。
C
1#define _CRT_SECURE_NO_WARNINGS 2#include <ctype.h> 3#include <stdbool.h> 4#include <stdio.h> 5#include <stdlib.h> 6 7// int型の数値の範囲ならtrueを返す 8bool isInt(const char strNumber[], const int strSize) { 9 10 // 先頭1桁目の数値判定と負数判定 11 bool flag_minus = false; 12 if (strNumber[0] == '-') { 13 flag_minus = true; 14 } else if (!(isdigit(strNumber[0]))) { 15 return false; 16 } 17 18 // 桁数取得 19 int digitSize = 0; 20 for (int i = 1; i < strSize; i++) { 21 if (strNumber[i] == '\0') { 22 digitSize = i; 23 break; 24 } 25 if (!(isdigit(strNumber[i]))) { 26 return false; 27 } 28 } 29 30 // 11桁以上または0桁以下は範囲外 31 if (digitSize < 1 || digitSize > (10 + flag_minus)) { 32 return false; 33 } 34 35 // int型最大値=2147483647 36 const int intMaxDigitNumbersPlus[10] = {2, 1, 4, 7, 4, 8, 3, 6, 4, 7}; 37 // int型最小値=-2147483648 38 const int intMaxDigitNumbersMinus[10] = {2, 1, 4, 7, 4, 8, 3, 6, 4, 8}; 39 40 if (flag_minus) { 41 // 10桁の場合のみ全桁チェック 42 if (digitSize == (11)) { 43 for (int i = 0; i < digitSize; i++) { 44 if (intMaxDigitNumbersMinus[i] < strNumber[i + 1] - '0') { 45 return false; 46 } else if (intMaxDigitNumbersMinus[i] == strNumber[i + 1] - '0') { 47 continue; 48 } else { 49 return true; 50 } 51 } 52 } 53 } else { 54 // 10桁の場合のみ全桁チェック 55 if (digitSize == (10)) { 56 for (int i = 0; i < digitSize; i++) { 57 if (intMaxDigitNumbersPlus[i] < strNumber[i] - '0') { 58 return false; 59 } else if (intMaxDigitNumbersPlus[i] == strNumber[i] - '0') { 60 continue; 61 } else { 62 return true; 63 } 64 } 65 } 66 } 67 68 // 正:10文字未満、または10文字で2147483647ならtrue 69 // 負:11文字未満、または11文字で-2147483648ならtrue 70 return true; 71} 72 73// int型の数値の最大値: 2147483647 74// int型の数値の最小値: -2147483648 75// int型の数値の範囲ならint型に変換する 76int main(void) { 77 char strNumber[256]; 78 while (scanf("%s", strNumber)) { 79 int strSize = 256; 80 // 先にint型範囲内の整数に変換可能かisInt()関数で判定する 81 // isInt()関数の結果がtrueならatoi()関数で文字列からint型の整数に変換して出力 82 int intNumber; 83 if (isInt(strNumber, strSize)) { 84 intNumber = atoi(strNumber); 85 printf("%d\n", intNumber); 86 } else { 87 printf("%s %s\n", strNumber, " は、int型ではありません。"); 88 } 89 } 90 getchar(); 91 return 0; 92}
txt
11234567890 21234567890 32147483647 42147483647 52147483648 62147483648 は、int型ではありません。 7-1234567890 8-1234567890 9-2147483648 10-2147483648 11-2147483649 12-2147483649 は、int型ではありません。 130 140 15abc 16abc は、int型ではありません。 17あいう 18あいう は、int型ではありません。 19
投稿2020/08/19 07:03
総合スコア303
0
負値は変換してないようなので、0 以下はあり得ないので
最大値だけで良さそうです。
#include <limits.h>
を追加して、
for(int i = 1; isdigit(suuji[i]); i++){
if((INT_MAX - (suuji[i] - '0'))/10 < seisuu) return 0; // 追加
seisuu *= 10;
seisuu += suuji[i] - '0';
}
くらいでいいのでは?
それまでの数値までだけ変換するのであれば
return 0; でなく break; にすればいいかな?
追加
n2q37_cppさんのソースに付加するのも気が引けるので
自分が書いたソースに付加しておきます
#include <stdio.h> #include <ctype.h> #include <limits.h> int str2value(const char *p) { char minus = 0; unsigned ret = 0; switch (*p) { case '-': minus = 1; case '+': p++; } unsigned limits = minus ? 0U - INT_MIN : INT_MAX; while (isdigit(*p)) { int no = *p++ - '0'; if ((limits - no) / 10 < ret) break; ret = ret * 10 + no; } return minus ? -ret : ret; } int main() { char str[16]; while (fgets(str, sizeof str, stdin)) printf("%d\n", str2value(str)); return 0; }
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10230218750?__ysp=c3RyMnZhbHVl
投稿2020/08/18 22:22
編集2020/08/19 13:35総合スコア478
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
#include <limits.h>
とすると、シンボル INT_MAX, INT_MINが使えるようになります。それぞれintの最大値、最小値です。
値を操作して桁あふれが発生してしまうと最大値以下の値(あるいは最小値より大きい値)になってしまうので、
「値を何かしら操作する前に、操作しても大丈夫なのかどうか」という形で検査を行う必要があります。
C
1 if(INT_MAX/10 >= seisuu){ 2 //10倍しても最大値を超えない 3 seisuu *= 10; 4 }else{ 5 //最大値を超える 6 seisuu = 0; 7 break; 8 } 9 if (INT_MAX - seisuu >= suuji[i] - '0') { 10 //足しても最大値を超えない 11 seisuu += suuji[i] - '0'; 12 } else { 13 //最大値を超える 14 seisuu = 0; 15 break; 16 }
下のプログラムでダメな部分
いうまでもなく、負数に対応していないところ。
「整数型の最小値よりも小さな値」を問題にするということは当然負の数も対象ですね?
while(scanf("%s", s) == 1){
ではループから脱出できないのでは。
ダメではないけれど、
char s[256];
は余裕がありすぎに思えます。
投稿2020/08/18 22:16
編集2020/08/19 12:44総合スコア7703
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/08/18 23:47
2020/08/19 03:34
2020/08/19 12:44
2020/08/19 13:39
2020/08/19 13:46
2020/08/19 13:48
2020/08/19 14:17
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。